A box with its words beside it that turns one setting or one answer on and off, such as "Show planned works on the map", ticked when it is on and dashed when it stands for a set that is partly on, and submitted with a form.
When to use
Use Checkbox for one answer or one setting that is on or off on its own, applied when the form is sent, such as agreeing to a notice.
| Use instead | When |
|---|---|
| CheckboxGroup | Several checkboxes answer one question together |
| Switch | The setting takes effect at once, such as showing vehicle trails on the map |
| FilterChip | The thing turned on and off is a filter on the map, which takes effect at once |
| RadioGroup | The answer is one choice among two to six |
| SegmentedControl | The choice is one of two to five ways to show one view |
Kongens Nytorv
Metro M1, M2 and M3.
Props
| Name | Type | Default | Description |
|---|---|---|---|
onChange | (event: Event, value: boolean, details: Checkbox.Root.ChangeEventDetails) => void | — | Called when a click or Space ticks or unticks the checkbox, with the new state as value; details.reason is 'none', and details.cancel() keeps the state as it was. event is details.event. Not called while disabled or read-only. |
children | ReactNode | — | The label: what ticking the box turns on or agrees to, in sentence case, such as "Show planned works on the map". It names the checkbox and stays the same ticked or not. Left out, give the checkbox an aria-label or aria-labelledby. |
className | string | — | Reaches the root, the <span role="checkbox">. className is merged after pn-Checkbox. |
style | CSSProperties | — | Reaches the root, the <span role="checkbox">. className is merged after pn-Checkbox. |
ref | Ref<HTMLElement> | — | Reaches the root, the <span role="checkbox">. className is merged after pn-Checkbox. |
slotProps | { indicator?: Omit<CheckboxIndicatorProps, "keepMounted" | "render"> | undefined; } | — | Props for each part: indicator. |
onChange(event: Event, value: boolean, details: Checkbox.Root.ChangeEventDetails) => void, default —- Called when a click or Space ticks or unticks the checkbox, with the new state as
value;details.reasonis'none', anddetails.cancel()keeps the state as it was.eventisdetails.event. Not called while disabled or read-only. childrenReactNode, default —- The label: what ticking the box turns on or agrees to, in sentence case, such as "Show planned works on the map". It names the checkbox and stays the same ticked or not. Left out, give the checkbox an
aria-labeloraria-labelledby. classNamestring, default —- Reaches the root, the
<span role="checkbox">.classNameis merged afterpn-Checkbox. styleCSSProperties, default —- Reaches the root, the
<span role="checkbox">.classNameis merged afterpn-Checkbox. refRef<HTMLElement>, default —- Reaches the root, the
<span role="checkbox">.classNameis merged afterpn-Checkbox. slotProps{ indicator?: Omit<CheckboxIndicatorProps, "keepMounted" | "render"> | undefined; }, default —- Props for each part:
indicator.
Use it
import { Checkbox } from '@mylder/perron'Ask your agent
get_reference({ library: "base-ui", component: "Checkbox" })Keyboard and ARIA
From the Base UI reference for Checkbox and the installed CheckboxRoot and useButton. "From" says who does it.
| Key | Does | From |
|---|---|---|
Tab, Shift+Tab | Moves focus to the checkbox and away; a disabled checkbox is skipped, a read-only one is not | The browser, and Base UI's tabIndex |
Space | Ticks or unticks the checkbox on release and calls onChange with the new state; its keydown doesn't scroll the page | Base UI |
Enter | Doesn't toggle; in a form, clicks the form's default submit button, as on a native checkbox | Base UI |
Checkbox adds no keys of its own. Checkboxes in a column are a tab stop each: each is an answer of its own.
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | checkbox, from Base UI; a native button with the checkbox role when render gives a <button> | Its text content, the label's children; the caller's aria-label or aria-labelledby win, and with no children, a <label htmlFor> on its id through Base UI's aria-labelledby | aria-checked, true, false or mixed; aria-disabled; aria-readonly; aria-required; aria-invalid inside an invalid Base UI field, on the root and the hidden input; with parent, aria-controls the ids of the checkboxes it controls |
indicator | none: presentational inside the checkbox, its mark an aria-hidden SVG | none | none |
label | none: text inside the checkbox | The checkbox's name | none |
| hidden input | none: aria-hidden, tabIndex −1, from Base UI | none | none |
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: the tick is
aria-checked="true", heard as "checked", the dasharia-checked="mixed", heard as "mixed" or "partially checked", the empty boxaria-checked="false"; the marks arearia-hidden, since the state says them; the tertiary colour of a disabled checkbox isaria-disabled; the danger edge of an invalid one is the field's error text andaria-invalid, never the edge alone. - Every landmark and named region has an accessible name: none here; a checkbox is neither. The group of checkboxes is CheckboxGroup's, inside a Fieldset whose legend names it.
- Every default label can be overridden: none here; Checkbox owns no strings.
- Every shape the type accepts renders, in every variant:
childrenrenders a string, an element and a list alike, ticked, unticked, indeterminate and disabled, and nothing at all when it renders nothing, leaving the box alone. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; the box kept mounted is the box itself, not a copy, and nothing collapses. - Native semantics first: Base UI's
role="checkbox"on a<span>, with a native<input type="checkbox">beside it for the form; withrenderandnativeButton, a native<button>. - Focus moves in reading order and returns on close: each checkbox is one tab stop in document order, focus stays on the checkbox it toggles, and it opens nothing to return from.
- Every target is at least
size.target-minsquare: the smallest target is a checkbox with no label, its rootsize.target-min(24 px) square round the 16 px box; with a label, the whole row is the target. - Loops stop when the system asks for less motion: none here; Checkbox has no loop and no transition.
Owned strings
No owned strings: every word comes from the caller, as children or an aria-label, and the state is heard from aria-checked, in the screen reader's own words.
Do and don't
For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | should | Use Checkbox for an answer or a setting that is on or off on its own, applied when the form is sent, such as agreeing to a notice | Use it for a filter on the map that takes effect at once: that is a FilterChip's, pressed and seen at once | review |
| DD-2 | must | Write the label as what ticking it turns on, in sentence case, the same ticked or not: "Show planned works on the map" | Write it as a question or a negative ("Don't show planned works?"): a tick on a negative reads backwards | review |
| DD-3 | must | Put a link about the setting next to the checkbox, outside its children | Put a link inside the label: a checkbox's content is flattened into its name, so the link can't be reached or pressed | review |
| DD-4 | should | Give name, and value where the form needs more than "on", so the answer reaches the form; connect a form library through its controller | Read the state back from the DOM or keep a hidden input of your own: Base UI's hidden input already carries it | review |
| DD-5 | must | Use indeterminate for a box that stands for a set partly on, such as "All lines" over the lines below it, and set it from the set's state, or give it parent inside a CheckboxGroup with allValues, which sets it for you | Use it as a third answer to one question: "mixed" says some of a set, and Space always turns it to ticked or unticked | review |
| DD-6 | must | Show why a box is invalid in words, from its field | Rely on the danger edge alone: colour is never the only sign (Accessibility) | review |
| DD-7 | must | Group related checkboxes in a CheckboxGroup, whose legend names the group | Make a list of checkboxes one tab stop, or use them for one choice among several: that is a radio group's or a SegmentedControl's | review |
| DD-8 | must | Keep onChange for the box's state, and cancel it with details.cancel() when the change must not happen | Set aria-checked yourself or toggle a class: Base UI keeps the state, the attribute and the input in step | review |