Checkbox

mandatory

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-muted unchecked)
  • *heck icon* 14 px, accent-on fill
  • *ndeterminate icon* horizontal dash, 12 px wide, accent-on
  • *it zone* 48×48 px (touch target, R5)
  • *abel*(when paired): 8 px gap, body-medium role

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 the

    input)

  • 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 error color
  • Helper text below with error message (per errors/user-facing-messages.kmd)
  • aria-invalid="true" + aria-describedby pointing at error text

R8 — Accessibility

  • <input type="checkbox"> element (NOT <div role="checkbox">)
  • Visible focus ring (R1)
  • Keyboard: Space toggles
  • Label association MANDATORY
  • aria-checked follows native input checked state (no need to set

    manually 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)

  • interaction/selection.kmd — multi-select patterns
  • interaction/states.kmd — focushoverpress visuals
  • themes/color-roles.kmd — accent + error tokens
  • errors/user-facing-messages.kmd — error format

Source: ../home/koder/dev/koder/meta/docs/stack/specs/components/checkbox.kmd