Checkbox
A checkbox whose check draws in, with indeterminate parents, groups and labels that share its hover.
pnpm dlx shadcn@latest add https://hextaui.com/r/checkbox.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @base-ui/react @tabler/icons-react cnCopy and paste the following code into your project.
components/ui/checkbox.tsx Update the import paths to match your project setup.
States
disabled, readOnly, indeterminate and aria-invalid. A read-only box keeps its value and stays focusable, but ignores clicks and keys.
Select all
Inside a <CheckboxGroup />, a checkbox with parent ticks every value in allValues. It turns indeterminate when only some are ticked.
Nested groups
Groups nest. Each parent reflects the state of the group directly below it, and the top parent covers everything.
Controlled
Pass checked and onCheckedChange to keep the state in your own code.
Form
A hidden input submits name and value like a native checkbox, and required blocks submit until it is ticked.
Sibling label
When the label can’t wrap the box, render the checkbox as a <button> with nativeButton and point the label at it with htmlFor.
Cards
Wrap a whole card in the label so the card is the hit area, and style it with has-data-checked.
Long content
The box stays on the first line while a long label and unbroken text wrap beside it.
Right to left
The box sits on the inline start side and the label follows the reading direction.
| Key | Action |
|---|---|
| Space | Ticks or unticks the checkbox. |
| Enter | Submits the form the checkbox belongs to, like a native checkbox. It never toggles the box. |
| Tab | Moves focus to the next checkbox. |
- Wrap the checkbox and its text in a
<label>. The label names the checkbox, and hovering or pressing it gives the box the same feedback as hovering the box itself. - Give every
<CheckboxGroup />anaria-labeloraria-labelledbyso screen readers announce what the group is for. - The hit area extends past the 16px box, and grows on touch screens.
- The check draws in when ticked. With reduced motion it appears without the stroke animation.
Built on the Base UI checkbox and checkbox group. Both accept the props of the primitive they wrap.
| Prop | Type | Default |
|---|---|---|
checked | boolean | – |
defaultChecked | boolean | false |
onCheckedChange | (checked: boolean, details) => void | – |
indeterminateShows a dash: neither ticked nor unticked. | boolean | false |
disabled | boolean | false |
readOnlyFocusable, but the value can’t change. | boolean | false |
required | boolean | false |
nameSubmitted with the form when ticked. | string | – |
valueIdentifies the box inside a group and is what the form submits. Falls back to name, then “on”. | string | – |
uncheckedValueSubmitted when unticked. Nothing by default. | string | – |
parentControls every value in the group’s allValues. Only inside a CheckboxGroup. | boolean | false |
inputRef | Ref<HTMLInputElement> | – |
nativeButtonSet to true when render is a <button>. | boolean | false |
render | ReactElement | (props, state) => ReactElement | <span> |
| Attribute | Description |
|---|---|
data-slot="checkbox" | Target the box in CSS. |
data-checked | Present when ticked. |
data-unchecked | Present when unticked. |
data-indeterminate | Present when indeterminate. |
data-disabled | Present when disabled. |
data-readonly | Present when read-only. |
data-required | Present when required. |
data-invalid | Present when invalid inside a Base UI Field. |
| Prop | Type | Default |
|---|---|---|
valueValues of the ticked checkboxes. | string[] | – |
defaultValue | string[] | – |
onValueChange | (value: string[], details) => void | – |
allValuesEvery value in the group. Required for a parent checkbox. | string[] | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="checkbox-group" | Target the group in CSS. |
data-disabled | Present when the group is disabled. |