<!-- https://getkonjo.com/design/components/checkbox · source: docs/design/components/checkbox.md -->

# Checkbox

A decision about a thing already on screen: send this note, include this student.

```kata-specimen
checkbox-states
```

> Source: [`Checkbox.tsx`](../../../src/components/ui/Checkbox.tsx). Spec:
> [form](../patterns/form.md), 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](tag-chip.md) or a sheet. Not for agreeing to
terms that carry liability: those follow [destructive](../patterns/destructive.md) 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.pressed` 0.85 on the row.
- **Focus**: a 2px `border.focus` ring 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](belt-dot.md) does.
- **Error**: a checkbox does not validate itself; the [field](input.md) or form around it does.

**On web the ring is the component's own.** `Checkbox` draws the 2px `border.focus` ring itself
(around the whole row, 2pt outside it), as an outline so focusing it moves nothing. It shows for keyboard focus only — a
mouse or touch press does not light it — and native, which has no keyboard focus, is unchanged.

## 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.control` on `surface.page` is 3.15:1 in light, so the empty box is visible on the page.

## Do and don't

```kata-specimen
checkbox-vs-chip
```

## Code

```tsx
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}`}
/>
```
