Forms & Controls
Accessible Checkbox (incl. tri-state)
A control allowing a binary or tri-state (checked/unchecked/mixed) choice.
Last verified against WCAG 2.2 and WAI-ARIA APG 1.2 on 2026-07-02.
Implementation
<!-- Native checkboxes give you the role, focus, Space to toggle, and
label association for free. "mixed" (indeterminate) is the one
state with no HTML attribute, you set it from JS (see the JS tab). -->
<ul>
<li>
<input type="checkbox" id="notify-all" />
<label for="notify-all">Notify me about everything</label>
</li>
<li>
<input type="checkbox" class="child" id="notify-email" />
<label for="notify-email">Email</label>
</li>
<li>
<input type="checkbox" class="child" id="notify-sms" />
<label for="notify-sms">SMS</label>
</li>
</ul>Required roles, states & properties
| Element | Attribute | Why |
|---|---|---|
| Checkbox <button> | role="checkbox" | Overrides the button's default semantics so AT announces "checkbox" and reads the state below instead of a generic pressed/not-pressed toggle. |
| Checkbox <button> | aria-checked="true"|"false"|"mixed" | The literal string "mixed" is what lets a screen reader announce "partially checked" for a parent whose children are only partly selected, a plain boolean can't express that third state. |
| Checkbox <button> | Accessible name (visible text or aria-label) | Every checkbox needs a programmatically associated name so AT can announce what is being checked, per SC 4.1.2 and 2.5.3 Label in Name. |
| Native <input type="checkbox"> | .indeterminate (DOM property, not an attribute) | Sets the visual mixed dash and the accessible "mixed" exposure for a native checkbox; must be set via ref in an effect since JSX has no matching prop. |
Keyboard interaction model
| Key | Behavior |
|---|---|
| Tab / Shift+Tab | Moves focus to the next/previous checkbox in the group. |
| Space | Toggles the focused checkbox. Enter is intentionally not bound, checkboxes only respond to Space, unlike buttons or links. |
Focus management rules
- Every checkbox in a group is individually focusable via Tab, there is no roving tabindex for checkboxes (unlike radio groups).
- Toggling a checkbox never moves focus away from it.
- A parent "select all" checkbox is never removed from the tab order, even while showing a mixed state.
WCAG 2.2 success criteria mapping
| SC | Name | Level | Why it applies |
|---|---|---|---|
| 1.3.1 | Info and Relationships | A | Structure and relationships conveyed visually are also programmatically determinable. |
| 2.1.1 | Keyboard | A | All functionality is operable through a keyboard interface with no specific timing. |
| 2.5.8 | Target Size (Minimum) | AA | Pointer targets are at least 24x24 CSS pixels, unless spaced, inline, or essential. |
| 3.3.2 | Labels or Instructions | A | Labels or instructions are provided when content requires user input. |
| 4.1.2 | Name, Role, Value | A | For all UI components, name, role, and value are programmatically determinable; states and changes are announced. |