# Checkbox

> Two-state checkbox. Standalone (boolean) or inside \<wr-checkbox-group> (array of values).

Source: https://ngwr.dev/reference/components/checkbox  
Kind: Component, Standalone

## Installation

```angular-ts
import { WrCheckbox, WrCheckboxGroup } from 'ngwr/checkbox';
import { FormsModule } from '@angular/forms';

@Component({ imports: [WrCheckbox, WrCheckboxGroup, FormsModule] })
export class MyComponent {}
```

## Standalone

Signal-forms native — bind the boolean `checked` model via `[(checked)]`, `[formField]`, or classic `[(ngModel)]`.

```html
<!-- signal-forms native: [(checked)], [formField], or classic [(ngModel)] -->
<wr-checkbox [(checked)]="agree">I agree</wr-checkbox>
```

## Inside a group

The group manages an array of values. Each child contributes its value when checked.

```html
<wr-checkbox-group [(value)]="features">
  <wr-checkbox checkboxValue="autosave">Autosave</wr-checkbox>
  <wr-checkbox checkboxValue="notifications">Notifications</wr-checkbox>
  <wr-checkbox checkboxValue="darkmode">Dark mode</wr-checkbox>
</wr-checkbox-group>
```

## Indeterminate

A parent `[indeterminate]` shows the mixed state (a dash) when only some children are checked — the classic 'select all'. It's visual and controlled: you set it, and clear it on the next toggle.

```html
<!-- A parent "select all": mixed when only some children are checked. -->
<wr-checkbox [checked]="allChecked()" (checkedChange)="toggleAll()" [indeterminate]="someChecked()">
  Select all
</wr-checkbox>
@for (p of permItems; track p) {
  <wr-checkbox [checked]="perms().includes(p)" (checkedChange)="togglePerm(p)">{{ p }}</wr-checkbox>
}
```

## Disabled

```html
<wr-checkbox [disabled]="true">Disabled</wr-checkbox>
```

## Use it in a form

Signal forms is the native path — `[formField]` binds the `checked` model directly. Reactive forms and `[(ngModel)]` go through [Angular 22's forms bridge](https://ngwr.dev/guides/forms), which binds a signal-forms control with no `ControlValueAccessor` involved: the library ships none, and `formControlName` still works. That bridge is not an accessor, and the guide is what it carries and what it drops — `updateOn`, `required`, and a `{ emitEvent: false }` write that never repaints. Mind which model each half binds, too: a single checkbox is a boolean, the group is the array of `checkboxValue`s.

```angular-html
<!-- Signal forms — the native path. -->
<wr-checkbox [formField]="form.agree">I agree</wr-checkbox>

<!-- Reactive forms. A single <wr-checkbox> is a FormCheckboxControl, so the
     control it binds holds a BOOLEAN — the checkbox's `checked` model, not
     `checkboxValue` (which is group identity and stays out of forms). -->
<form [formGroup]="form">
  <wr-checkbox formControlName="agree">I agree to the terms</wr-checkbox>

  <!-- A <wr-checkbox-group> is a FormValueControl<unknown[]>, so ITS control
       holds the array of checked `checkboxValue`s. -->
  <wr-checkbox-group formControlName="features">
    <wr-checkbox checkboxValue="autosave">Autosave</wr-checkbox>
    <wr-checkbox checkboxValue="notifications">Notifications</wr-checkbox>
  </wr-checkbox-group>
</form>

<!-- Template-driven — the same bridge. -->
<wr-checkbox [(ngModel)]="agree" name="agree">I agree</wr-checkbox>
```

```angular-ts
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';

import { WrCheckbox, WrCheckboxGroup } from 'ngwr/checkbox';

@Component({
  imports: [ReactiveFormsModule, WrCheckbox, WrCheckboxGroup],
  templateUrl: './my.html',
})
export class MyComponent {
  protected readonly form = new FormGroup({
    agree: new FormControl(false, { nonNullable: true, validators: [Validators.requiredTrue] }),
    features: new FormControl<string[]>(['autosave'], { nonNullable: true }),
  });
}
```

## Checkbox API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `id` | Stable id used to associate the native input with its label. Lands on the inner `<input>`; the host never keeps it. | `string` | `Randomly generated` |
| `checkboxValue` | This checkbox's identity when inside a `<wr-checkbox-group>` — the value added to / removed from the group's array. Ignored in standalone mode. (Named `checkboxValue`, not `value`, because `FormCheckboxControl` reserves `value`.) | `unknown` | `null` |
| `ariaLabel` | Accessible name for a checkbox used WITHOUT projected text — a selection cell in a table, say. The wrapping `<label>` names the control whenever content is projected; with none, the native input has no name, and an `aria-label` put on the host lands on a `<wr-checkbox>` element that no screen reader ever announces. | `string \| null` | `null` |
| `checked` | Checked state — the form value. Bound by `[formField]`, two-way via `[(checked)]`, or `[(ngModel)]`. Ignored inside a `<wr-checkbox-group>`, where the group's array is the source of truth. | `boolean` | `false` |
| `(touch)` | Emitted on blur so a bound field can mark itself touched. | `void` | — |
| `disabled` | Disable the checkbox. Bound automatically from the field's disabled state when used with `[formField]`. | `boolean` | `false` |
| `readonly` | Refuse edits while staying focusable and submittable. Bound automatically from the field's readonly state when used with `[formField]`. A native `<input type="checkbox">` ignores the `readonly` attribute, so this cancels the click's activation behaviour instead — which covers Space too, since a checkbox turns Space into a click — and mirrors the state as `aria-readonly`, which role `checkbox` supports. | `boolean` | `false` |
| `size` | Control size — shares the `--wr-control-*` contract. Unset falls back to the `checkbox.size` app default from `provideWrConfig()`. | `WrCheckboxSize \| null` | `'md'` |
| `icon` | Optional icon name rendered inside the box when checked, in place of the default checkmark. Use any registered NGWR icon. | `WrIconName \| null` | `null` |
| `indeterminate` | Show the indeterminate ("mixed") state — a dash instead of a check. Visual only and controlled: set it yourself for a parent "select all" whose children are partly checked, and clear it on the next toggle. Takes visual precedence over `checked`; the native input reports `aria-checked="mixed"`. | `boolean` | `false` |

## Checkbox Group API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `disabled` | Disable every child checkbox. Bound automatically from the field's disabled state when used with `[formField]`. | `boolean` | `false` |
| `readonly` | Refuse edits on every child while they stay focusable and the value still submits. Bound automatically from the field's readonly state when used with `[formField]`. No `aria-readonly` on the host: role `group` does not support it (the state is not global), so each child box mirrors its own instead. | `boolean` | `false` |
| `value` | The checked items' values. Bound by `[formField]`, or two-way via `[(value)]`. | `unknown[]` | `[]` |
| `(touch)` | Emitted when a child toggles so a bound field can mark itself touched. | `void` | — |

## CSS variables

Custom properties `ngwr/checkbox` publishes. Each default below is declared on the component's own selector, so a `:root` override is shadowed by it — set them on that selector, on a wrapper you scope yourself, or inline on the element. Unlike the BEM class names, these are the supported way to restyle the component.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-checkbox-bg` | `var(--wr-color-surface)` | `.wr-checkbox` +2 variant overrides |
| `--wr-checkbox-border` | `var(--wr-color-outline)` | `.wr-checkbox` +3 variant overrides |
| `--wr-checkbox-color` | `var(--wr-color-on-surface)` | `.wr-checkbox` +1 variant override |
| `--wr-checkbox-font-size` | `var(--wr-text-sm)` | `.wr-checkbox` +2 variant overrides |
| `--wr-checkbox-line-height` | `var(--wr-control-line-height-md)` | `.wr-checkbox` +2 variant overrides |
| `--wr-checkbox-mark` | `transparent` | `.wr-checkbox` +2 variant overrides |
| `--wr-checkbox-radius` | `var(--wr-control-radius-md)` | `.wr-checkbox` +2 variant overrides |
| `--wr-checkbox-size` | `1.125rem` | `.wr-checkbox` +2 variant overrides |
