Checkbox

A control that allows the user to toggle between checked and not checked.

Preview Code

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.

Angular CLInpmpnpmyarnbun
Bash
ng g @ng-cn/core:c checkbox

Anatomy

Import all parts and piece them together.

Typescript
import { Checkbox } from '@/ui/checkbox';
Html
<Checkbox id="terms" />

API Reference

Checkbox

The main checkbox component. Implements ControlValueAccessor for Angular Forms.

PropTypeDefault
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

AttributeValues
[data-state]"checked" | "unchecked" | "indeterminate"
[data-disabled]Present when disabled

Examples

Basic

A simple checkbox with default styling.

Html
<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.

Html
<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.

Html
<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.

Html
<!-- 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.

Html
<!-- 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.

Html
<!-- 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

KeyDescription
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.