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
PropTypeDefaultDescriptionPlatforms
label requiredstring—

Visible label. Clicking or tapping it toggles the control.

Accessibility: Programmatically associated with the control (label/for on web, accessibilityLabel on native).

web, lit, rn, swiftui
hideLabelbooleanfalse

Visually hide the label (it remains the accessible name): a selection column in a Table, where the row name is the label.

web, lit, rn, swiftui
name requiredstring—

Field name used by the enclosing Form when collecting values.

web, lit, rn, swiftui
valuestringon

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.

web, lit, rn, swiftui
checkedboolean—

Controlled checked state. Omit for an uncontrolled control.

web, lit, rn, swiftui
defaultCheckedbooleanfalse

Initial state for an uncontrolled control.

web, lit, rn, swiftui
indeterminatebooleanfalse

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").

web, lit, rn, swiftui
disabledbooleanfalse

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.

web, lit, rn, swiftui
requiredbooleanfalse

Must be checked to submit — for consent and agreement. Shown in the label, not only by color.

web, lit, rn, swiftui
invalidbooleanfalse

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.

web, lit, rn, swiftui
descriptionstring—

Persistent helper text below the label.

Accessibility: Linked with aria-describedby / accessibilityHint.

web, lit, rn, swiftui
errorstring—

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.

web, lit, rn, swiftui

Events

1 row
EventTypeDescriptionPlatforms
onChangeonChange / change

Fired when the checked state changes, with the new boolean.

web, lit, rn, swiftui

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

controlindicatorlabeldescriptionerrorMessage

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.

Contrast pairs

6 rows
ForegroundBackgroundLevel
color.control.selectedForegroundcolor.control.selectedBackgroundAA
color.control.selectedBackgroundcolor.backgroundAA (non-text)
color.control.bordercolor.backgroundAA (non-text)
color.foregroundcolor.backgroundAA
color.foreground.mutedcolor.backgroundAA
color.foreground.dangercolor.backgroundAA

This component does not animate, so it has no reduced-motion behaviour to describe.