Checkbox
A labelled on/off control for a single option, with tri-state support for "some selected", a description, and an error message that is announced.
Basic usage
Install the package:
pnpm add @design-schema/react @design-schema/tokens Import the stylesheet once for the app, then the component:
import '@design-schema/tokens/calm-precise/css';
import '@design-schema/react/index.css';
import { Checkbox } from '@design-schema/react'; Examples
import { Checkbox } from '@design-schema/react';
<Checkbox label="Send me product updates" name="updates" />Props
12 rows| Prop | Type | Default | Description |
|---|---|---|---|
| label required | string | — | Visible label. Clicking or tapping it toggles the control. Accessibility: Programmatically associated with the control (label/for on web, accessibilityLabel on native). |
| hideLabel | boolean | false | Visually hide the label (it remains the accessible name): a selection column in a Table, where the row name is the label. |
| name required | string | — | Field name used by the enclosing Form when collecting values. |
| value | string | on | What a native HTML <form> submits under `name` when checked (web and Lit only). The enclosing Form (React, React Native, ds-form) ignores it and collects the boolean `checked`. Checkboxes sharing a `name` are not a multi-select under Form; give each its own name. React Native accepts it (default 'on') for API parity and does nothing with it. |
| checked | boolean | — | Controlled checked state. Omit for an uncontrolled control. |
| defaultChecked | boolean | false | Initial state for an uncontrolled control. |
| indeterminate | boolean | false | Shows the mixed indicator, for a parent checkbox whose children are partly selected. Visual and announced only; the submitted value still follows `checked`. With `checked` also true, mixed wins for both the glyph and the announced state — a partly selected parent is mixed, whatever its own box would say — while the submitted value stays `checked`. Accessibility: Announced as "mixed" (aria-checked=mixed / accessibilityState checked "mixed"). |
| disabled | boolean | false | Cannot be toggled and is skipped by the Form. Stays visible, readable and focusable, which is why it is `aria-disabled` and not the native attribute — with the accepted consequence that a native HTML `<form>` still submits a disabled-but-checked box's `value`, since only the native attribute excludes it. Accessibility wins over that edge; the Form component, which collects fields itself, skips it either way. |
| required | boolean | false | Must be checked to submit — for consent and agreement. Shown in the label, not only by color. |
| invalid | boolean | false | Marks the control as failing validation. Usually set by the Form; can be set directly. While true with no `error` (and no Form message), the error slot renders copy.required (required and unchecked) or copy.invalid, with role=alert, so a bare `invalid` always shows a message. |
| description | string | — | Persistent helper text below the label. Accessibility: Linked with aria-describedby / accessibilityHint. |
| error | string | — | The error message. Setting it marks the control invalid. Say what to do ("Accept the terms to continue"). Accessibility: Rendered in the error slot with aria-describedby and role=alert. |
Events
1 row| Event | Type | Description |
|---|---|---|
| onChange | onChange / change | Fired when the checked state changes, with the new boolean. |
Accessibility
Decisions this component leaves to you
Supply the label. It is associated with the control for you, but the words are yours — a placeholder is not a label.
Supply the error text when the value is invalid. The component links and announces it; it cannot write it.
Required props that carry accessibility meaning: label. Each is described in the props table above.
Implicit ARIA role: checkbox.
Anatomy
What generation guarantees
Label association — The label is programmatically associated with the control, not merely placed beside it.
Error identification — An invalid value is identified in text and linked to the control — never signalled by colour alone.
Visible focus — Keyboard focus is always drawn, from the theme’s focus tokens, and is never removed.
Keyboard operable — Everything the pointer can do here, the keyboard can do — see the keyboard section.
Target size — Interactive targets are at least 24×24 CSS pixels (WCAG 2.2 Target Size, minimum).
Contrast — Text and meaningful non-text contrast meets WCAG AA; the pairs are listed below.
This component does not animate, so it has no reduced-motion behaviour to describe.