Skip to content

Find what you need, instantly

Search components, ARIA roles & attributes, and WCAG criteria.

Forms & Controls

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

checkbox-pattern.tsx
function CheckboxBox({ state, label, onToggle }) {
  // state: "true" | "false" | "mixed"
  return (
    <button
      type="button"
      role="checkbox"
      aria-checked={state === "mixed" ? "mixed" : state === "true"}
      onClick={onToggle}
      onKeyDown={e => {
        if (e.key === " ") { e.preventDefault(); onToggle(); }
      }}
    >
      <span aria-hidden="true" className="box">
        {state === "true" && <CheckIcon />}
        {state === "mixed" && <DashIcon />}
      </span>
      {label}
    </button>
  );
}

// Parent state is always DERIVED from children, never stored separately:
const parentState = allChecked ? "true" : noneChecked ? "false" : "mixed";

Live demo

Required roles, states & properties

Required roles, states, and properties
ElementAttributeWhy
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

Keyboard interaction model
KeyBehavior
Tab / Shift+TabMoves focus to the next/previous checkbox in the group.
SpaceToggles 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

WCAG 2.2 success criteria that apply to this component
SCNameLevelWhy it applies
1.3.1Info and RelationshipsAStructure and relationships conveyed visually are also programmatically determinable.
2.1.1KeyboardAAll functionality is operable through a keyboard interface with no specific timing.
2.5.8Target Size (Minimum)AAPointer targets are at least 24x24 CSS pixels, unless spaced, inline, or essential.
3.3.2Labels or InstructionsALabels or instructions are provided when content requires user input.
4.1.2Name, Role, ValueAFor all UI components, name, role, and value are programmatically determinable; states and changes are announced.

References