Checkbox

Atom
Multi-select option, single yes/no, grouped lists.

Playground

Every control sets a real prop of CheckboxProps. The JSX below updates as you go.
Props
checked
boolean
indeterminate
boolean
Size
pick one
disabled
boolean
children
string
description
string
JSX · CheckboxProps
<Checkbox
checked
description="One message per stable version"
>
Email me release notes
</Checkbox>

Variants

5 examples from src/atoms/checkbox/checkbox.md, each rendered live from its own JSX.
Unchecked
<Checkbox>Email notifications</Checkbox>
Disabled
<Checkbox disabled>Email notifications</Checkbox>
Sizes
<Column>
<Checkbox small defaultChecked>Small</Checkbox>
<Checkbox defaultChecked>Default</Checkbox>
<Checkbox large defaultChecked>Large</Checkbox>
</Column>
With description
<Checkbox defaultChecked description="Get notified when activity happens on your account.">
Email notifications
</Checkbox>
Nested group
A parent "select all" over a group of children: a list selection, so every box takes selection. Wire the parent's checked and indeterminate from the children's state: checked when every child is on, indeterminate when only some are, and toggling the parent selects or clears the whole group. (Stateful is a docs-only state holder so this fence can show the controlled wiring; in an app that state lives in your own component.)
<Stateful initial={["Read"]}>
{(selected, setSelected) => {
const perms = ["Read", "Write", "Delete"];
const all = perms.every((p) => selected.includes(p));
const some = selected.length > 0 && !all;
return (
<Column>
<Checkbox
selection
checked={all}
indeterminate={some}
onChange={(next) => setSelected(next ? perms : [])}
>
Select all
</Checkbox>
<Column indent>
{perms.map((p) => (
<Checkbox
key={p}
selection
checked={selected.includes(p)}
onChange={(next) =>
setSelected(next ? [...selected, p] : selected.filter((x) => x !== p))
}
>
{p}
</Checkbox>
))}
</Column>
</Column>
);
}}
</Stateful>

Sizes

small
default
large

States

Hover, focus and press are pinned so they can be compared side by side; the rest are real props.
default
hover
focus
disabled

Anatomy

1
Box
2
Check mark
3
Label
4
Description
Dimmed parts appear only in some states or variants.

Props

15 props on CheckboxProps, grouped as they are declared in source. Required props are marked *.
Prop
Type
Default
Description
Props
11 props
children
ReactNode
–
Label text (the option's title) shown beside the box.
description
ReactNode
–
Optional muted secondary line rendered under the label, for the common title-plus-description option (a notification setting, a consent row). Supplying it builds the stacked title/description layout inside the control, so the caller never hand-composes a Row + Column + two Typography nodes and the whole row stays tappable.
checked
boolean
false
Controlled checked state; omit for uncontrolled use.
defaultChecked
boolean
false
Initial state for uncontrolled use (a bare <Checkbox /> is interactive).
indeterminate
boolean
false
Mixed state: some-but-not-all selected. Shown as a dash, not a tick. Takes visual precedence over checked. Implies selection: a mixed state belongs to a list's select-all, and a switch has none.
selection
boolean
false
A checkbox that selects an item in a list or a bulk selection (a table's rows, a list in edit mode, a select-all), rather than one on/off setting. The web draws the checkbox, iOS the edit-mode selection circle, Android the Material 3 checkbox. Without it a Checkbox is one setting, which iOS and Android render as their switch (role switch), so a settings row reads the way each platform writes it.
onChange
(next: boolean) => void
–
Fired with the next checked value when the row is pressed (both modes). Web keyboard activation supports Space on release and Enter.
onValueChange
(next: boolean) => void
–
Alias of onChange, for parity with RN's value-style callbacks.
accessibilityLabel
string
–
Accessible name for a LABEL-LESS checkbox (one with no children, e.g. a row selector in a table). With a visible label the label itself is the name; without one this is what a screen reader announces.
testID
string
–
E2E hook forwarded to the pressable row.
ref
React.Ref<View>
–
Ref to the interactive checkbox row, including its label. Typed as a React Native View. On web, React Native Web exposes its DOM host; focus() and blur() move browser focus. Native host behavior depends on the platform and React Native version. Calling focus() does not activate the control or call accessibility focus APIs.
Size
pick one
2 props
small
boolean
false
large
boolean
false
State
2 props
disabled
boolean
false
State.
style
LayoutStyle
–
Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds.

Accessibility and keyboard

Keyboard
Space
Toggles
Tab
Moves focus on
Semantics
Roles
checkbox
States
checked
disabled
ARIA on web
aria-checked
aria-label
Below the platform minimum, the touch area grows to 44 pt on iOS and 48 dp on Android without moving the layout.
From the docs
Pass ref to access the interactive checkbox row, including its label. Use useRef<ComponentRef<typeof Checkbox>>(null) from React, or useRef<View>(null) with React Native's View type. Object and callback refs are supported and detach on unmount. Calling ref.current?.focus() or .blur() delegates to the host without activating the control. Browser focus is supported; native focus depends on the platform and React Native version, and is separate from accessibility focus.
On the web, Space activates the focused control on key release, and Enter also activates it. Holding Space does not repeat the change. Moving focus away, disabling the control, or composing text cancels a pending Space press.

Platform skins

The playground's props on each platform: same tree, native shapes, type and touch sizes.
Web
control 10 · field 10 · card 16 · Instrument Sans
Small
Default
Large
iOS
capsule controls · field 8 · card 12 · SF Pro · 44 pt
Small
Default
Large
Android
Material 3 stadium · field 4 · card 12 · Roboto · 48 dp

Usage

<Checkbox defaultChecked>Email notifications</Checkbox>
One job, a platform's own control: a Checkbox that is one setting (a yes/no, a consent, an opt-in) renders the platform's switch on iOS and Android, where a single setting is a switch (Material 3 on phones included), and stays a checkbox on the web; its role follows what renders (switch there, checkbox here). A Checkbox that selects items in a list, a table's rows or a "select all" parent takes selection: the web keeps the checkbox, Android the Material 3 checkbox, and iOS draws the edit-mode selection circle. indeterminate implies selection, since a mixed state belongs to a "select all" parent and a switch has none. In glass mode the box keeps its solid look on every platform: it is a small mark inside content, not a surface, so it draws with no pane and no rim, a checked box in its solid brand fill under its check and an empty box with its solid outline.
Pass ref to access the interactive checkbox row, including its label. Use useRef<ComponentRef<typeof Checkbox>>(null) from React, or useRef<View>(null) with React Native's View type. Object and callback refs are supported and detach on unmount. Calling ref.current?.focus() or .blur() delegates to the host without activating the control. Browser focus is supported; native focus depends on the platform and React Native version, and is separate from accessibility focus.
On the web, Space activates the focused control on key release, and Enter also activates it. Holding Space does not repeat the change. Moving focus away, disabling the control, or composing text cancels a pending Space press.

Tokens

Read from the playground render. Values follow the scheme and the ion hue.
--fd
--ft
--ion
--ion-fg
--tx3

Related components