Checkbox
Binary or tri-state selection control built on Radix Checkbox, with indeterminate support and form-payload semantics.
Overview
Checkbox is built on @radix-ui/react-checkbox. It supports the three canonical states - unchecked, checked, and indeterminate - via Radix's checked prop, which accepts true | false | "indeterminate". The indicator renders a CheckIcon from lucide.
Use Checkbox when the value is part of a form submission (terms acceptance, multi-select filters, table row selection). Reach for Switch instead when the change takes effect immediately, without submission (notifications on / off, dark mode).
Preview
'use client';import { Checkbox, Label } from '@gremorie/rx-forms';export function CheckboxPreview() { return ( <div className="flex items-center gap-2"> <Checkbox id="cb-demo" defaultChecked /> <Label htmlFor="cb-demo">Subscribe to the changelog</Label> </div> );}Anatomy
Checkbox 4×4 rounded box; renders the check glyph when checkedInstallation
bash npx gremorie@latest add rx-checkbox bash pnpm dlx gremorie@latest add rx-checkbox bash yarn dlx gremorie@latest add rx-checkbox bash bunx --bun gremorie@latest add rx-checkbox Usage
import { Checkbox, Label } from "@gremorie/rx-forms";
export function Example() {
return (
<div className="flex items-center gap-2">
<Checkbox id="terms" />
<Label htmlFor="terms">Accept terms and conditions</Label>
</div>
);
}The Angular edition of this component ships from source today (see the workbench for the side-by-side); its registry entry is coming next.
API
<Checkbox>
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | "indeterminate" | - | Controlled checked state. Pass "indeterminate" for the dash indicator. |
defaultChecked | boolean | "indeterminate" | - | Uncontrolled initial state. |
onCheckedChange | (checked: boolean | "indeterminate") => void | - | Fires when the user toggles the checkbox. |
disabled | boolean | false | Disables interaction. |
required | boolean | false | Mark as required for form submission. |
name | string | - | Form field name. |
value | string | "on" | Form field value when checked. |
aria-invalid | boolean | - | Switches border / ring to destructive token. |
Forwards all props to CheckboxPrimitive.Root and renders a CheckboxPrimitive.Indicator with a CheckIcon inside. The data-state attribute (unchecked, checked, indeterminate) drives the visual surface.
Composition
- Always pair with a
<Label>viahtmlFormatching the checkbox'sid. The label is the affordance most users click. - Inside a
<Form>, use<FormField>with<FormControl>so ARIA wiring happens automatically. - For "select all" patterns, drive the master checkbox into
indeterminatewhen some (but not all) children are checked.
Variations
With label and description
The canonical form pattern: checkbox, label, and an optional helper line. Clicking the label toggles the control.
You agree to our Terms of Service and Privacy Policy.
'use client';import { Checkbox, Label } from '@gremorie/rx-forms';export function CheckboxWithLabelPreview() { return ( <div className="flex items-start gap-3"> <Checkbox id="cb-terms" defaultChecked /> <div className="grid gap-1.5 leading-none"> <Label htmlFor="cb-terms">Accept terms and conditions</Label> <p className="text-sm text-muted-foreground"> You agree to our Terms of Service and Privacy Policy. </p> </div> </div> );}States
The three canonical states - unchecked, checked, and indeterminate - side by side. Indeterminate renders the dash indicator and announces as "mixed".
'use client';import { Checkbox, Label } from '@gremorie/rx-forms';export function CheckboxStatesPreview() { return ( <div className="flex flex-col gap-3"> <div className="flex items-center gap-2"> <Checkbox id="cb-unchecked" /> <Label htmlFor="cb-unchecked">Unchecked</Label> </div> <div className="flex items-center gap-2"> <Checkbox id="cb-checked" defaultChecked /> <Label htmlFor="cb-checked">Checked</Label> </div> <div className="flex items-center gap-2"> <Checkbox id="cb-indeterminate" defaultChecked="indeterminate" /> <Label htmlFor="cb-indeterminate">Indeterminate</Label> </div> </div> );}Indeterminate "select all"
Master checkbox flips to indeterminate when some children are selected. Clicking it should clear all when indeterminate / checked, and select all when unchecked.
function SelectAll({ items, selected, onChange }) {
const allSelected = selected.length === items.length;
const someSelected = selected.length > 0 && !allSelected;
return (
<div className="flex items-center gap-2">
<Checkbox
id="select-all"
checked={allSelected ? true : someSelected ? 'indeterminate' : false}
onCheckedChange={(value) => {
onChange(value === true ? items.map((i) => i.id) : []);
}}
/>
<Label htmlFor="select-all">Select all</Label>
</div>
);
}Disabled
Label reads peer-disabled and fades automatically when the sibling peer-marked checkbox is disabled. Radix's Checkbox.Root includes the peer class, so both the unchecked and checked locked states stay legible.
'use client';import { Checkbox, Label } from '@gremorie/rx-forms';export function CheckboxDisabledPreview() { return ( <div className="flex flex-col gap-3"> <div className="flex items-center gap-2"> <Checkbox id="cb-disabled-off" disabled /> <Label htmlFor="cb-disabled-off">Disabled, unchecked</Label> </div> <div className="flex items-center gap-2"> <Checkbox id="cb-disabled-on" disabled defaultChecked /> <Label htmlFor="cb-disabled-on">Disabled, checked</Label> </div> </div> );}Accessibility
- Native semantics: Radix renders
role="checkbox"witharia-checkedreflecting the state (true,false,mixedfor indeterminate). - Keyboard:
Spacetoggles the checkbox;Tab/Shift+Tabmove focus. - Label association: clicking the
<Label>toggles the checkbox via the standardhtmlFormechanism. - Indeterminate:
aria-checked="mixed"is announced as "mixed" by screen readers, signalling partial selection. - Required + invalid: combine
requiredwitharia-invalid="true"and an error message; the destructive ring kicks in automatically.
Related
- Switch - immediate-effect toggle (vs form-submission selection)
- Radio Group - single-select cousin
- Label - the canonical companion
- Form - wire Checkbox into react-hook-form