Components

A checkbox — a token-styled wrapper over Base UI's Checkbox. Sharp-cornered, navy when checked, with the shared focus ring; supports the indeterminate state (a dash) for "some selected" headers. Pair it with a <label> for an accessible name — the box itself doesn't carry one.

Install

npx shadcn@latest add @alix/checkbox

Preview

Usage

<label className="flex items-center gap-2 text-sm">
  <Checkbox defaultChecked /> Mark as received
</label>

Examples

01

Checked and disabled states

Use native checked and disabled props for static form defaults and locked workflow choices.

<label className="flex items-center gap-2 text-sm">
  <Checkbox /> Include people updates
</label>
<label className="flex items-center gap-2 text-sm">
  <Checkbox defaultChecked /> Include delivery risks
</label>
<label className="flex items-center gap-2 text-sm text-muted-foreground">
  <Checkbox defaultChecked disabled /> Approved by client
</label>
02

Indeterminate group header

Indeterminate communicates that some, but not all, nested choices are selected.

<label className="flex items-center gap-2 text-sm font-medium">
  <Checkbox indeterminate /> Capability filters
</label>
<div className="ml-6 flex flex-col gap-2">
  <label className="flex items-center gap-2 text-sm">
    <Checkbox defaultChecked /> Turnaround and restructuring
  </label>
  <label className="flex items-center gap-2 text-sm">
    <Checkbox /> Performance improvement
  </label>
</div>
03

Filter group with count

Controlled checkboxes pair with Badge when a filter panel needs immediate selection feedback.

Capability filters2 selected
const [selected, setSelected] = useState({
  restructuring: true,
  performance: false,
  transactions: true,
});
const selectedCount = Object.values(selected).filter(Boolean).length;

return (
  <div className="w-full max-w-sm border border-border p-4">
    <div className="mb-4 flex items-center justify-between gap-4">
      <span className="text-sm font-medium text-foreground">Capability filters</span>
      <Badge variant="primary">{selectedCount} selected</Badge>
    </div>
    <div className="flex flex-col gap-3">
      <label className="flex items-center gap-2 text-sm">
        <Checkbox
          checked={selected.restructuring}
          onCheckedChange={(checked) =>
            setSelected((current) => ({ ...current, restructuring: checked }))
          }
        />
        Turnaround and restructuring
      </label>
      <label className="flex items-center gap-2 text-sm">
        <Checkbox
          checked={selected.performance}
          onCheckedChange={(checked) =>
            setSelected((current) => ({ ...current, performance: checked }))
          }
        />
        Performance improvement
      </label>
      <label className="flex items-center gap-2 text-sm">
        <Checkbox
          checked={selected.transactions}
          onCheckedChange={(checked) =>
            setSelected((current) => ({ ...current, transactions: checked }))
          }
        />
        Transactions and investor services
      </label>
    </div>
  </div>
);

When to use it

Use it for

  • Independent yes/no choices, filter lists, and permission toggles where multiple values can be selected.
  • Indeterminate parent rows that summarize a partially selected group.
  • Visible labels beside the box so the control has an accessible name.

Reach for something else

  • A single constrained choice from a list — use Select instead.
  • Action menus with commands or links — use Menu instead.
  • Status display with no interaction — use Badge instead.

Props

PropTypeDefaultDescription
checked / defaultCheckedbooleanControlled / uncontrolled checked state (Base UI props, forwarded).
onCheckedChange(checked: boolean) => voidFires when the box toggles.
indeterminatebooleanfalseRenders a dash instead of a check — the "some selected" state for group headers.
name / valuestringForwarded for native form submission.

See also