A decision about a thing already on screen: send this note, include this student.
Light
Unchecked
Send to AnaChecked
Send to AnaPressed
Send to AnaFocus
Send to AnaDark
Unchecked
Send to AnaChecked
Send to AnaPressed
Send to AnaFocus
Send to AnaSource:
Checkbox.tsx. Spec: form, selection controls.
When to use it
- Yes or no about one specific thing beside it: "Send to Ana" under a note.
- A list of independent yes/no decisions, each with its own label.
Not for picking a value from a set — that is a chip or a sheet. Not for agreeing to terms that carry liability: those follow destructive and are never pre-checked.
Anatomy
| Part | Token |
|---|---|
| Row | the whole row is the target, touchTarget 44 floor, spacing.s8 box to label |
| Box | 24 square, radius.input 8, 1px border.control, transparent |
| Checked box | brand.red fill and edge, a check glyph at iconSize.inline 16 in brand.onRed |
| Label | typography.body 15/400, text.primary, wraps |
States
- Unchecked and checked as drawn. State is carried by the check glyph — a shape — not by the fill alone, so it survives without colour.
- Pressed:
opacity.pressed0.85 on the row. - Focus: a 2px
border.focusring around the row. - Disabled: the prop exists and only stops the press. Avoid it — say why the option is not available in the label instead, as RankPicker does.
- Error: a checkbox does not validate itself; the field or form around it does.
On web the ring is the browser's. Checkbox does not draw its own focus ring; on RN-web it relies on
the browser's default focus outline. Input, SearchField and SelectTrigger draw the 2px
border.focus themselves; the specimen shows the ring this component owes.
Content
- Sentence case, a complete statement of what checking does: "Send to Ana", not "Ana".
- When the visible label is short because context supplies the rest, give the full sentence as
accessibilityLabel: "Send note 2 to Ana Torres".
Accessibility
- Role
checkbox,accessibilityState={{ checked, disabled }}. - The label is the target, not the box. A 24pt box alone is under 44pt, and making people hit the box while the words beside it do nothing is the most common way this control is built wrong.
border.controlonsurface.pageis 3.15:1 in light, so the empty box is visible on the page.
Do and don't
Do
A checkbox decides something about a thing already on screen.
Don’t
A chip standing in for a checkbox reads as a filter.
Code
import { Checkbox } from '../../components/ui';
<Checkbox
checked={note.send}
onChange={(send) => updateNote(note.id, { send })}
label="Send to Ana"
accessibilityLabel={`Send note ${index + 1} to Ana Torres`}
testID={`promotion-note-send-${index}`}
/>