Checkbox
Binary toggle in a multi-select context — user marks 0..N options. Material parity (`/components/checkbox/overview`). 18×18 px tap target wrapped in 48 px hit zone; 3 states (unchecked, checked, indeterminate); WAI-ARIA-compliant.
Spec — Checkbox
Facet *isual*do Koder Design. Material parity: https://m3.material.io/components/checkbox/overview.
Anatomy
☐ Unchecked
☑ Checked (filled accent square + white check icon)
☒ Indeterminate (filled accent square + dash icon)- *ox* 18×18 px (default), 2 px border (
text-mutedunchecked) - *heck icon* 14 px,
accent-onfill - *ndeterminate icon* horizontal dash, 12 px wide,
accent-on - *it zone* 48×48 px (touch target, R5)
- *abel*(when paired): 8 px gap,
body-mediumrole
R1 — States (visual)
Per interaction/states.kmd:
| State | Box bg | Box border | Icon |
|---|---|---|---|
| Unchecked + enabled | transparent | text-muted (2 px) |
— |
| Unchecked + hover | text-muted 8% bg |
text-muted |
— |
| Unchecked + focused | + focus ring | accent |
— |
| Checked + enabled | accent |
accent |
accent-on check |
| Checked + hover | accent-strong |
accent-strong |
accent-on |
| Checked + focused | + focus ring | accent |
accent-on |
| Indeterminate | accent |
accent |
accent-on dash |
| Disabled (any) | 38% opacity | 38% opacity | 38% opacity |
| Error | error border |
error |
error (if checked) |
R2 — Single checkbox (boolean toggle)
Use when the user toggles ONE thing on/off (terms acceptance, notification opt-in).
☐ I agree to the Terms of Service.- Label to the right (left in RTL)
- Whole row clickable (label is a
<label for="id">or wraps theinput)
- Don't use a Switch instead — Switch implies immediate effect
(toggle WiFi), checkbox implies "this value as part of a form"
R3 — Multi-select list
Use within a list when user picks 0..N items.
☑ Inbox
☐ Spam
☑ Drafts
☐ Sent- Per
interaction/selection.kmd— list-row pattern - Whole row clickable (not just the checkbox)
- Long-press on mobile enters select mode; subsequent taps toggle
- Bulk action bar appears when ≥ 1 checked
R4 — Indeterminate state
Represents partial selection (e.g., a parent of a tree with some children checked).
☒ All projects ← indeterminate (some children checked)
☐ Project A
☑ Project B
☑ Project C- Visual: dash icon (not check)
- Behavior on click: depends on convention — Koder default:
indeterminate → unchecked → checked → unchecked (3-cycle)
- Programmatic only — user can't directly SET indeterminate; it's
derived from children state
aria-checked="mixed"
R5 — Touch target
- Visible box: 18×18 px
- Hit zone: 48×48 px (touch target per
safe-area.kmd) - When in a list row: entire row is the hit zone; checkbox box is
visual anchor
R6 — Label association
<!-- ✅ Wrapped (preferred) -->
<label>
<input type="checkbox"> I agree
</label>
<!-- ✅ Linked via for -->
<input type="checkbox" id="agree">
<label for="agree">I agree</label>
<!-- ❌ Separate without association -->
<input type="checkbox">
<span>I agree</span>R7 — Error state
When a required checkbox is unchecked at submit:
- Box border
errorcolor - Helper text below with error message (per
errors/user-facing-messages.kmd) aria-invalid="true"+aria-describedbypointing at error text
R8 — Accessibility
<input type="checkbox">element (NOT<div role="checkbox">)- Visible focus ring (R1)
- Keyboard: Space toggles
- Label association MANDATORY
aria-checkedfollows native input checked state (no need to setmanually unless using ARIA-only widget)
- Screen reader announces: "Checkbox, Inbox, checked" (or unchecked,
or indeterminate)
R9 — Per-preset variation
| Preset | Box style |
|---|---|
material3 |
Square + radius-xs (2 px), 2 px border |
material2 |
Square + sharp corners, 2 px border |
ios_cupertino |
Circle (radius-full), 1.5 px border |
gnome |
Square + radius-xs, single 1 px border |
windows_95 |
3D bevel border, sharp corners, no radius |
brutalist |
Sharp corners, 3 px thick border |
terminal_classic |
ASCII [ ] / [x] |
R10 — Forbidden patterns
- ❌ Custom checkbox without standard semantic (rebuilding from
<div>) - ❌ Checkbox without label (always provide accessible name)
- ❌ Toggling between checkbox and switch styling per-row in same list
- ❌ "Required" indicator on checkbox row (it's binary — error on
submit, not visual asterisk)
Cross-link
interaction/selection.kmd— multi-select patternsinteraction/states.kmd— focushoverpress visualsthemes/color-roles.kmd— accent + error tokenserrors/user-facing-messages.kmd— error format