Creating an Angular Component Library - Checkbox Component
Published on
We can use the same process as we did with the toggle to create other form controls as well. We’ll create a similar control to the toggle but it will visually resemble a checkbox.
Prerequisites
- Install Node
- Install Angular CLI
- Creating an Angular Component Library - Workspace Setup
- OR Clone this github repository
Generating Our Checkbox
For our checkbox we will need to generate a module, component and several enum values which we will use to provide different values to customize our checkbox based on size, shape, color and label position.
We’ll use the Angular CLI to generate our module and component…
ng generate module components/checkbox --project=foo
ng generate component components/checkbox --project=foo
We need to update our module file to export our component to make it available to importing modules…
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CheckboxComponent } from './checkbox.component';
@NgModule({
declarations: [
CheckboxComponent
],
imports: [
CommonModule
],
exports: [
CheckboxComponent
]
})
export class CheckboxModule { }
Now we can create our enum values that will be used for differenct configurations for a checkbox.
ng generate enum components/checkbox/checkbox-color --project=foo
ng generate enum components/checkbox/checkbox-label-position --project=foo
ng generate enum components/checkbox/checkbox-shape --project=foo
ng generate enum components/checkbox/checkbox-size --project=foo
We’ll again break out our SCSS into smaller files to keep things more readable and maintainable….
touch projects/foo/src/lib/components/checkbox/_checkbox-colors.scss \
projects/foo/src/lib/components/checkbox/_checkbox-label-positions.scss \
projects/foo/src/lib/components/checkbox/_checkbox-shapes.scss \
projects/foo/src/lib/components/checkbox/_checkbox-sizes.scss
Now we just need to update our components
directory’s public_api.ts
file…
export * from './checkbox/checkbox-color.enum';
export * from './checkbox/checkbox-label-position.enum';
export * from './checkbox/checkbox-shape.enum';
export * from './checkbox/checkbox-size.enum';
export * from './checkbox/checkbox.component';
export * from './checkbox/checkbox.module';
Creating Our Enum Values
Our enum values simply map to CSS classes to apply the appropriate styles to the checkbox component…
Our colors enum…
export enum CheckboxColor {
PRIMARY = 'checkbox-color-primary',
SECONDARY = 'checkbox-color-secondary',
SUCCESS = 'checkbox-color-success',
INFO = 'checkbox-color-info',
WARNING = 'checkbox-color-warning',
DANGER = 'checkbox-color-danger'
}
Our label positioning enum…
export enum CheckboxLabelPosition {
LEFT = 'checkbox-label-position-right',
RIGHT = 'checkbox-label-position-left'
}
Our shape enum…
export enum CheckboxShape {
SQUARE = 'checkbox-shape-square',
ROUNDED = 'checkbox-shape-rounded',
CIRCLE = 'checkbox-shape-circle'
}
And finally our size enum…
export enum CheckboxSize {
SMALL = 'checkbox-size-small',
MEDIUM = 'checkbox-size-medium',
LARGE = 'checkbox-size-large'
}
Creating Out Checkbox Component
We going to have our component implement the ControlValueAccessor
interface that Angular provides to us just like we did with our toggle switch.
Our component class file… @@@ TODO say more…
import { Component, Input, forwardRef } from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { CheckboxColor } from "./checkbox-color.enum";
import { CheckboxSize } from "./checkbox-size.enum";
import { CheckboxShape } from "./checkbox-shape.enum";
import { CheckboxLabelPosition } from "./checkbox-label-position.enum";
@Component({
selector: "foo-checkbox",
templateUrl: "./checkbox.component.html",
styleUrls: ["./checkbox.component.scss"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxComponent),
multi: true
}
]
})
export class CheckboxComponent implements ControlValueAccessor {
@Input()
public label: string;
@Input()
public labelPosition: CheckboxLabelPosition;
@Input()
public shape: CheckboxShape;
@Input()
public size: CheckboxSize;
@Input()
public color: CheckboxColor;
@Input()
public disabled: boolean;
@Input()
public set value(isChecked: boolean) {
if (!this.disabled) {
this.isChecked = isChecked;
this.onChange(isChecked);
}
}
public isChecked: boolean = false;
public onChange: any = () => {};
public onTouch: any = () => {};
constructor() {
this.labelPosition = CheckboxLabelPosition.RIGHT;
this.shape = CheckboxShape.ROUNDED;
this.size = CheckboxSize.MEDIUM;
this.color = CheckboxColor.PRIMARY;
this.disabled = false;
}
public registerOnChange(fn: any): void {
this.onChange = fn;
}
public registerOnTouched(fn: any): void {
this.onTouch = fn;
}
public writeValue(checked: boolean): void {
this.isChecked = checked;
}
public setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
public toggleChecked(isChecked: boolean): void {
if (!this.disabled) {
this.isChecked = !this.isChecked;
this.onChange(this.isChecked);
}
}
public get classes(): string {
return `${this.labelPosition} ${this.shape} ${this.size} ${this.color}`;
}
}
Our HTML template…
<div class="checkbox-container" [ngClass]="classes">
<div class="checkbox"
[ngClass]="{ 'checked' : isChecked }"
(click)="toggleChecked()">
<div class="checkmark">✖</div>
</div>
<label class="checkbox-label">{{ label || '' }}</label>
</div>
Now there is quite a bit of styling for our checkbox hence why we chose to break our out SCSS into small files instead of throwing all the SCSS into one file.
We’ll pull in our SASS variables file for each scss files. Our _checkbox-colors.scss
file will look something like…
@import '../_shared/scss/variables';
@mixin create-checkbox-color($color) {
.checkbox {
&.checked {
background: $color;
&:hover {
background: darken($color, 10%);
}
&:active {
background: darken($color, 15%);
}
}
}
}
@mixin generate-checkbox-colors {
&.checkbox-color-primary {
@include create-checkbox-color($primary);
}
&.checkbox-color-secondary {
@include create-checkbox-color($secondary);
}
&.checkbox-color-success {
@include create-checkbox-color($success);
}
&.checkbox-color-info {
@include create-checkbox-color($info);
}
&.checkbox-color-warning {
@include create-checkbox-color($warning);
}
&.checkbox-color-danger {
@include create-checkbox-color($danger);
}
}
Our _label-positions.scss
file…
@import '../_shared/scss/variables';
@mixin generate-checkbox-label-positions {
&.checkbox-label-position-left {
flex-direction: row;
.checkbox-label {
margin-left: 0.25rem;
}
}
&.checkbox-label-position-right {
flex-direction: row-reverse;
justify-content: flex-end;
.checkbox-label {
margin-right: 0.25rem;
}
}
}
Our _checkbox-shapes.scss
file…
@import '../_shared/scss/variables';
@mixin create-checkbox-shape($radius) {
.checkbox{
border-radius: $radius;
.checkmark {
border-radius: $radius;
}
}
}
@mixin generate-checkbox-shapes {
&.checkbox-shape-square {
@include create-checkbox-shape(0);
}
&.checkbox-shape-rounded {
@include create-checkbox-shape(4px);
}
&.checkbox-shape-circle {
@include create-checkbox-shape(3rem);
}
}
Our _checkbox-sizes.scss
file…
@import '../_shared/scss/variables';
@mixin create-checkbox-size($checkbox-size, $font-size) {
.checkbox {
width: $checkbox-size;
height: $checkbox-size;
font-size: $font-size;
.checkmark {
line-height: $checkbox-size;
}
}
.checkbox-label {
font-size: $font-size;
line-height: $checkbox-size;
}
}
@mixin generate-checkbox-sizes {
&.checkbox-size-small {
@include create-checkbox-size(22px, 1rem);
}
&.checkbox-size-medium {
@include create-checkbox-size(32px, 1.2rem);
}
&.checkbox-size-large {
@include create-checkbox-size(42px, 1.5rem);
}
}
And finally our checkbox.component.scss
file…
@import '../_shared/scss/variables';
@import './_checkbox-colors';
@import './_checkbox-shapes';
@import './_checkbox-sizes';
@import './_checkbox-label-positions';
.checkbox-container {
display: inline-flex;
.checkbox {
box-sizing: border-box;
background: lighten($default, 20%);
color: $card-background;
transition: background 0.2s, visibility 0.2s;
cursor: pointer;
.checkmark {
visibility: hidden;
width: 100%;
height: 100%;
text-align: center;
vertical-align: middle;
}
&:hover {
background: lighten($default, 15%);
}
&:active {
background: lighten($default, 10%);
}
&.checked {
.checkmark {
visibility: visible;
}
}
}
@include generate-checkbox-label-positions;
@include generate-checkbox-colors;
@include generate-checkbox-sizes;
@include generate-checkbox-shapes;
}
Stackblitz Result
Below is an embeded Stackblitz showing our checkbox being used with our [dashabord layout][14] we create a few posts back. I’ve created two examples, one with our checkbox being used in a reactive form and the other being used with a template driven form.
The completed github repository can be found here
More Posts
- Creating an Angular Component Library - Workspace Setup
- Creating an Angular Component Library - Alert Component
- Creating an Angular Component Library - Progress Bar Component
- Creating an Angular Component Library - Toaster Component
- Creating an Angular Component Library - Card Component
- Creating an Angular Component Library - Flip Card Component
- Creating an Angular Component Library - Overlay Loader Component
- Creating an Angular Component Library - Overlay Side Panel Component
- Creating an Angular Component Library - Button Component
- Creating an Angular Component Library - Toggle Switch Component
- Creating an Angular Component Library - Checkbox Component