Run the CLI
Use the CLI to add the component to your project.
npx @ngzard/ui@latest add checkboxA control that allows the user to toggle between checked and not checked.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ZardCheckboxComponent } from '../checkbox.component';
@Component({
selector: 'z-demo-checkbox-default',
imports: [ZardCheckboxComponent, FormsModule],
template: `
<span z-checkbox></span>
<span z-checkbox [(ngModel)]="checked">Default Checked</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoCheckboxDefaultComponent {
checked = true;
}
Use the CLI to add the component to your project.
npx @ngzard/ui@latest add checkboxpnpm dlx @ngzard/ui@latest add checkboxyarn dlx @ngzard/ui@latest add checkboxbunx @ngzard/ui@latest add checkboxCreate the component directory structure and add the following files to your project.
import {
booleanAttribute,
ChangeDetectionStrategy,
Component,
computed,
forwardRef,
input,
output,
signal,
ViewEncapsulation,
} from '@angular/core';
import { type ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import type { ClassValue } from 'clsx';
import { ZardIdDirective } from '@/shared/core';
import { mergeClasses, noopFn } from '@/shared/utils/merge-classes';
import {
checkboxLabelVariants,
checkboxVariants,
type ZardCheckboxShapeVariants,
type ZardCheckboxSizeVariants,
type ZardCheckboxTypeVariants,
} from './checkbox.variants';
import { ZardIconComponent } from '../icon/icon.component';
type OnTouchedType = () => void;
type OnChangeType = (value: boolean) => void;
@Component({
selector: 'z-checkbox, [z-checkbox]',
imports: [ZardIconComponent, ZardIdDirective],
template: `
<main class="relative flex" zardId="checkbox" #z="zardId">
<input
#input
type="checkbox"
name="checkbox"
[id]="z.id()"
[class]="classes()"
[checked]="checked()"
[disabled]="disabled()"
(blur)="onCheckboxBlur()"
(click)="onCheckboxChange()"
/>
<z-icon
zType="check"
[class]="
'text-primary-foreground pointer-events-none absolute top-1/2 left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center transition-opacity ' +
(checked() ? 'opacity-100' : 'opacity-0')
"
/>
</main>
<label [class]="labelClasses()" [for]="z.id()">
<ng-content />
</label>
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ZardCheckboxComponent),
multi: true,
},
],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
host: {
'[class]': "(disabled() ? 'cursor-not-allowed' : 'cursor-pointer') + ' flex items-center gap-2'",
'[attr.aria-disabled]': 'disabled()',
},
exportAs: 'zCheckbox',
})
export class ZardCheckboxComponent implements ControlValueAccessor {
readonly checkChange = output<boolean>();
readonly class = input<ClassValue>('');
readonly zDisabled = input(false, { transform: booleanAttribute });
readonly zType = input<ZardCheckboxTypeVariants>('default');
readonly zSize = input<ZardCheckboxSizeVariants>('default');
readonly zShape = input<ZardCheckboxShapeVariants>('default');
private onChange: OnChangeType = noopFn;
private onTouched: OnTouchedType = noopFn;
protected readonly classes = computed(() =>
mergeClasses(checkboxVariants({ zType: this.zType(), zSize: this.zSize(), zShape: this.zShape() }), this.class()),
);
readonly disabledByForm = signal(false);
protected readonly labelClasses = computed(() => mergeClasses(checkboxLabelVariants({ zSize: this.zSize() })));
protected readonly disabled = computed(() => this.zDisabled() || this.disabledByForm());
readonly checked = signal(false);
writeValue(val: boolean): void {
this.checked.set(val);
}
setDisabledState(isDisabled: boolean): void {
this.disabledByForm.set(isDisabled);
}
registerOnChange(fn: OnChangeType): void {
this.onChange = fn;
}
registerOnTouched(fn: OnTouchedType): void {
this.onTouched = fn;
}
onCheckboxBlur(): void {
this.onTouched();
}
onCheckboxChange(): void {
if (this.disabled()) {
return;
}
this.checked.update(v => !v);
this.onChange(this.checked());
this.checkChange.emit(this.checked());
}
}
import { cva, type VariantProps } from 'class-variance-authority';
export const checkboxVariants = cva(
'cursor-[unset] peer appearance-none border transition shadow hover:shadow-md focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50',
{
variants: {
zType: {
default: 'border-primary checked:bg-primary',
destructive: 'border-destructive checked:bg-destructive',
},
zSize: {
default: 'size-4',
lg: 'size-6',
},
zShape: {
default: 'rounded',
circle: 'rounded-full',
square: 'rounded-none',
},
},
defaultVariants: {
zType: 'default',
zSize: 'default',
zShape: 'default',
},
},
);
export const checkboxLabelVariants = cva('cursor-[unset] text-current empty:hidden select-none', {
variants: {
zSize: {
default: 'text-base',
lg: 'text-lg',
},
},
defaultVariants: {
zSize: 'default',
},
});
export type ZardCheckboxShapeVariants = NonNullable<VariantProps<typeof checkboxVariants>['zShape']>;
export type ZardCheckboxSizeVariants = NonNullable<VariantProps<typeof checkboxVariants>['zSize']>;
export type ZardCheckboxTypeVariants = NonNullable<VariantProps<typeof checkboxVariants>['zType']>;
export * from './checkbox.component';
export * from './checkbox.variants';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ZardCheckboxComponent } from '../checkbox.component';
@Component({
selector: 'z-demo-checkbox-default',
imports: [ZardCheckboxComponent, FormsModule],
template: `
<span z-checkbox></span>
<span z-checkbox [(ngModel)]="checked">Default Checked</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoCheckboxDefaultComponent {
checked = true;
}
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ZardCheckboxComponent } from '../checkbox.component';
@Component({
selector: 'z-demo-checkbox-destructive',
imports: [ZardCheckboxComponent, FormsModule],
template: `
<span z-checkbox zType="destructive"></span>
<span z-checkbox zType="destructive" [(ngModel)]="checked">Destructive Checked</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoCheckboxDestructiveComponent {
checked = true;
}
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ZardCheckboxComponent } from '../checkbox.component';
@Component({
selector: 'z-demo-checkbox-size',
imports: [ZardCheckboxComponent, FormsModule],
standalone: true,
template: `
<span z-checkbox>Default</span>
<span z-checkbox zSize="lg" [(ngModel)]="checked">Large</span>
`,
})
export class ZardDemoCheckboxSizeComponent {
checked = true;
}
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ZardCheckboxComponent } from '../checkbox.component';
@Component({
selector: 'z-demo-checkbox-shape',
imports: [ZardCheckboxComponent, FormsModule],
template: `
<span z-checkbox zShape="circle" [(ngModel)]="checked1">Circle</span>
<span z-checkbox zShape="square" [(ngModel)]="checked2">Square</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoCheckboxShapeComponent {
checked1 = true;
checked2 = true;
}
import { ChangeDetectionStrategy, Component, type OnInit } from '@angular/core';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ZardCheckboxComponent } from '../checkbox.component';
@Component({
selector: 'z-demo-checkbox-disabled',
imports: [ZardCheckboxComponent, FormsModule, ReactiveFormsModule],
template: `
<div class="flex flex-col gap-8">
<form [formGroup]="form">
<span z-checkbox formControlName="acceptTerms">Accept Terms</span>
<span z-checkbox formControlName="newsletter">Subscribe</span>
</form>
<div>
<span z-checkbox [zDisabled]="true">Disabled</span>
<span z-checkbox [zDisabled]="true" [(ngModel)]="checked">Disabled</span>
</div>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoCheckboxDisabledComponent implements OnInit {
checked = true;
form = new FormGroup({
acceptTerms: new FormControl(false),
newsletter: new FormControl(false),
});
ngOnInit() {
this.form.disable();
}
}