Skip to Content
ComponentsCheckbox

Checkbox

Supports an indeterminate state in addition to true/false.

Anatomy

import { Checkbox } from "@spacing-ui/core"; <Checkbox defaultChecked="indeterminate" onCheckedChange={(c) => console.log(c)}> Accept terms </Checkbox>;

API

PropTypeDefaultDescription
checked / defaultCheckedboolean | "indeterminate"false
onCheckedChange(checked: boolean | "indeterminate") => void
disabledbooleanfalse

Accessibility

  • role="checkbox", aria-checked="true", "false", or "mixed"
  • Space toggles (clicking indeterminate advances to true)

Examples

Controlled with form state

const [accepted, setAccepted] = useState(false); <form onSubmit={(e) => { e.preventDefault(); submit(accepted); }}> <Checkbox checked={accepted} onCheckedChange={(v) => setAccepted(v === true)}> I accept the terms </Checkbox> <button type="submit" disabled={!accepted}>Continue</button> </form>

Native form submission

Pass a name and the checkbox will participate in native form data:

<form action="/subscribe" method="post"> <Checkbox name="marketing" defaultChecked>Receive updates</Checkbox> <button type="submit">Subscribe</button> </form>

The indeterminate state submits as unchecked.

Live demo

Indeterminate → checked → unchecked

Space (or click) on an indeterminate checkbox advances to true, matching the browser’s native tri-state cycle. From true, Space toggles to false.

Testing

const box = screen.getByRole("checkbox", { name: /accept/i }); expect(box).toHaveAttribute("aria-checked", "mixed"); await userEvent.click(box); expect(box).toHaveAttribute("aria-checked", "true");
Last updated on