Checkbox
Checkboxes allow users to select one or more options from a set, or toggle a single binary choice. Supports indeterminate state for partial selection patterns.
Keyboard interaction
| Key | Action |
|---|---|
| Tab | Move focus to the checkbox. |
| Shift + Tab | Move focus to the previous focusable element. |
| Space | Toggle the checkbox. If indeterminate, transitions to checked on first press. No-op when disabled. |
Screen reader behaviour
The component uses a native <input type="checkbox"> inside Shadow DOM with delegatesFocus: true. Screen readers announce the correct role automatically without any extra ARIA attributes.
| Attribute / Property | Value / Behaviour |
|---|---|
role | checkbox (implicit from native <input type="checkbox">) |
aria-checked | "true" when checked, "false" when unchecked. Set to "mixed" automatically when indeterminate={true}. |
aria-disabled | Not set — native disabled attribute is used instead, which is equivalent for screen readers. |
aria-describedby | Automatically set to the message element ID when state is "error" or "success" and a message is provided. |
aria-required | Not needed — native required attribute is passed to the inner <input>, which conveys the same semantics. |
WCAG 2.2 compliance
1.4.3 Contrast (Minimum) — AAPass
Label text uses --diwa-text-primary. Error/success border colours meet 3:1 non-text contrast against backgrounds.
1.4.11 Non-text Contrast — AAPass
The checkbox border (--diwa-border on dark: zinc-700; on light: zinc-300+) has ≥ 3:1 contrast against adjacent surface colours.
2.1.1 Keyboard — APass
All states are reachable and togglable via keyboard alone (Tab + Space).
2.4.7 Focus Visible — AAPass
A tokenized focus outline (var(--diwa-focus-ring-width) solid --diwa-border-focus) is always shown on keyboard focus via :focus-visible.
4.1.2 Name, Role, Value — APass
Native checkbox semantics are preserved; label prop provides the accessible name; indeterminate sets aria-checked="mixed".
1.3.1 Info and Relationships — APass
Error/success messages are linked via aria-describedby so they are announced to screen readers along with the input.
Best practices
- Always provide a label. The
labelprop is required for an accessible control. Usehide-labelonly when a visible label cannot fit the layout — the text is still present in the accessibility tree. - Derive indeterminate from state, do not set it imperatively. The component clears the
indeterminateattribute on user click. Compute it from your data model (someChecked && !allChecked) and pass it as a prop so it re-derives correctly after each state change. - Pair error state with a meaningful message. Setting
state="error"alone (without amessageprop) changes the border colour but provides no accessible feedback. Always include a human-readable message that is linked viaaria-describedby. - Disabled ≠ read-only. A disabled checkbox is excluded from form submission and cannot be focused by default. If you need to allow focus (e.g. to show a tooltip explaining why it is unavailable), use custom CSS
pointer-events: noneinstead and manage the visual disabled appearance yourself.