Checkbox

Toggle for independent options. One shape in the whole app since 28 Sep 2026 (owner approved v2; replaces D6 of 22 Aug 2026, which kept a native box in forms and a drawn box in menus). React <Checkbox> (packages/ui/src/components/Checkbox.tsx) draws the box .acrm-checkbox over a transparent native input.acrm-check-input inside span.acrm-checkfield — the native input carries the form value, keyboard, screen reader and the tap; the box is only the picture. Menu rows (CheckMenu, Add to list, Multi-select, Record select) render the same box with state classes. CSS: apps/web/src/ds/inputs.css §9.

When to use

  • Selecting items: rows in tables and pickers (bare <Checkbox aria-label>), items in menus and lists (the box on the right of a menu row), permissions of a role.
  • One or more independent options in a form that are choices, not properties of the record: "Only verified phone numbers", "Search in notes".
  • A "select all" that reflects a partial selection — indeterminate prop.

When not to use

  • Turning a property of the record on or off (Active, Track opens, Default for the domain) — that is a Switch (owner/AD 28 Sep 2026: checkbox is for selecting items).
  • Exactly one option out of several — Radio or Segmented control.
  • Several tags from a small set as clickable labels — Option chips.
  • A bare <input type="checkbox"> or the old native .acrm-check — pnpm ds:validate:usage fails (HARD, rule checkbox-native-no-ds); use <Checkbox>.

Anatomy

  • Box .acrm-checkbox: 16×16px, border-radius: 5px (ratio of the compact button 8/24; ds-ok, no token — AD), border: 1.5px solid var(--fg-secondary), background: var(--surface-100) (--surface-50 dark).
  • Check glyph: 12px (--ico-2xs), stroke-width: 3.5 on the 24 grid (≈1.75px — the bold check the owner chose), hidden with visibility until on.
  • On / mixed: --accent fill and border, white check / minus. Driven by the input (:checked, :indeterminate) or by .is-on / .is-mixed on menu rows.
  • Disabled: border --ink-400, fill --line-100; disabled + on/mixed = --ink-400 fill. Input :disabled or .is-disabled on menu rows.
  • Hover (enabled, off): border --accent.
  • <Checkbox> markup: span.acrm-checkfield > input.acrm-check-input + span.acrm-checkbox[aria-hidden]; with label wrapped in label.acrm-check-label (inline-flex, gap: var(--sp-3), var(--small), --fg-secondary) with the text in a <span>.
  • Props: all of <input> except type, plus label, indeterminate, ref (to the native input).
  • Table row selection (label.sgb-ck > input + .ck) draws the same box (5px, 1.5px --fg-secondary, bold check), revealed on row hover.

Best practices

Do

  • Label every checkbox: label prop in forms, aria-label for a bare box in a row.
  • Use indeterminate only on a parent that summarises children ("Select all" with some rows on).
  • Group related options under one <Field label>, stacked with gap: var(--sp-2).

Don't

  • A checkbox for a property that is simply on/off — Switch.
  • Restyling the box per screen (size, colour, radius) or a local .check clone — one shape.
  • Opposite phrasing ("Do not send e-mails") — label the positive state.

Content

  • Label in sentence case, states what is selected: "Only verified phone numbers", "Mentions in notes".
  • No trailing period; short phrase, wrap allowed.
  • A group label is a noun ("Notifications"); details go to the field hint, not the label.
  • switch — property on/off (Active, Track opens).
  • radio — one choice out of several.
  • multi-select, check-menu — the same box on the right of a list item.
  • Stories: components--checkbox--default, --variants, --states (incl. indeterminate, disabled), --composition; legacy overview components--inputs--checkboxes.

Source: docs/choice/checkbox.usage.md · GitLab