Checkbox
A control that allows the user to toggle between checked and not checked.
Interactive
Features
Supports indeterminate state. Full keyboard navigation. Can be controlled or uncontrolled. Works with Angular Forms (ControlValueAccessor). Accessible by default (WAI-ARIA).
Installation
Install the component from your command line.
ng g @ng-cn/core:c checkboxAnatomy
Import all parts and piece them together.
import { Checkbox } from '@/ui/checkbox';<Checkbox id="terms" />API Reference
Checkbox
The main checkbox component. Implements ControlValueAccessor for Angular Forms.
| Prop | Type | Default |
|---|---|---|
| id | string | — |
| The id attribute for the checkbox input - used for label association. | ||
| checked | boolean | "indeterminate" | false |
| The controlled state of the checkbox. Use with two-way binding: [(checked)]="value". | ||
| disabled | boolean | false |
| When true, prevents the user from interacting with the checkbox. | ||
| class | string | — |
| Additional CSS classes to apply to the checkbox. |
Data Attributes
| Attribute | Values |
|---|---|
| [data-state] | "checked" | "unchecked" | "indeterminate" |
| [data-disabled] | Present when disabled |
Examples
Basic
A simple checkbox with default styling.
<div class="flex items-center gap-2">
<Checkbox id="terms" />
<label for="terms" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
Accept terms and conditions
</label>
</div>Checked
A checked checkbox with default styling.
<div class="flex items-center gap-2">
<Checkbox id="checked" [checked]="true" />
<label for="checked" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
Terms accepted
</label>
</div>Disabled
A disabled checkbox with reduced opacity.
<div class="flex items-center gap-2">
<Checkbox id="disabled" disabled />
<label for="disabled" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
Disabled checkbox
</label>
</div>With two-way binding
Use two-way binding to control the checkbox state.
<!-- In your component class -->
isAgreed = signal(false);
<!-- In your template -->
<div class="flex items-center gap-2">
<Checkbox id="agree" [(checked)]="isAgreed" />
<label for="agree" class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
I agree to the terms
</label>
</div>
<Button [disabled]="!isAgreed()" (click)="submit()">
Submit
</Button>With Reactive Forms
Use the checkbox with Angular Reactive Forms.
<!-- In your component class -->
form = this.fb.group({
terms: [false, Validators.requiredTrue],
newsletter: [false],
});
constructor(private fb: FormBuilder) {}
<!-- In your template -->
<form [formGroup]="form">
<div class="flex items-center gap-2">
<Checkbox id="terms" formControlName="terms" />
<label for="terms" class="text-sm font-medium leading-none">
I accept the terms and conditions
</label>
</div>
<div class="flex items-center gap-2 mt-4">
<Checkbox id="newsletter" formControlName="newsletter" />
<label for="newsletter" class="text-sm font-medium leading-none">
Subscribe to our newsletter
</label>
</div>
<Button
type="submit"
[disabled]="form.invalid"
class="mt-4"
>
Submit
</Button>
</form>Indeterminate state
A checkbox with an indeterminate state - useful for parent checkboxes in a list.
<!-- In your component class -->
selectAll = signal<boolean | 'indeterminate'>('indeterminate');
items = signal([
{ id: 1, label: 'Item 1', checked: false },
{ id: 2, label: 'Item 2', checked: true },
{ id: 3, label: 'Item 3', checked: false },
]);
toggleSelectAll() {
const newState = this.selectAll() === true ? false : true;
this.items.update(items =>
items.map(item => ({ ...item, checked: newState }))
);
this.selectAll.set(newState);
}
toggleItem(id: number) {
this.items.update(items =>
items.map(item =>
item.id === id ? { ...item, checked: !item.checked } : item
)
);
const checkedCount = this.items().filter(i => i.checked).length;
const total = this.items().length;
if (checkedCount === 0) {
this.selectAll.set(false);
} else if (checkedCount === total) {
this.selectAll.set(true);
} else {
this.selectAll.set('indeterminate');
}
}
<!-- In your template -->
<div class="space-y-4">
<div class="flex items-center gap-2 p-4 border rounded-lg">
<Checkbox
id="select-all"
[checked]="selectAll()"
(click)="toggleSelectAll()"
/>
<label for="select-all" class="text-sm font-medium">
Select all items
</label>
</div>
<div class="space-y-2 pl-4">
@for (item of items(); track item.id) {
<div class="flex items-center gap-2">
<Checkbox
[id]="'item-' + item.id"
[checked]="item.checked"
(click)="toggleItem(item.id)"
/>
<label [for]="'item-' + item.id" class="text-sm">
{{ item.label }}
</label>
</div>
}
</div>
</div>Accessibility
Adheres to the Checkbox WAI-ARIA design pattern .
Keyboard Interactions
| Key | Description |
|---|---|
| Space | When focus is on the checkbox, toggles between checked and unchecked. |
| Tab | Moves focus to the next focusable element. |
| Shift + Tab | Moves focus to the previous focusable element. |