Checkbox
FreeA native checkbox with a clear checked, unchecked and indeterminate state.
pnpm dlx shadcn@latest add https://caliperui.site/r/checkbox.jsonWhen to use #
Use it for
- Independent yes/no options that are saved with a form.
- A parent that summarises a list of children, using indeterminate.
Skip it when
- The change applies instantly; use a switch.
- Exactly one option must be chosen; use radios.
Installation #
terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/checkbox.json
Adds the file to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
example.tsx
import { useState } from "react" import { Checkbox } from "@/components/ui/checkbox" import { Label } from "@/components/ui/label" export function NotificationChecks() { const [events, setEvents] = useState({ paid: true, failed: true, refund: false }); const count = Object.values(events).filter(Boolean).length; const rows = [ { key: "paid", label: "Invoice paid", hint: "Receipt with PDF attached" }, { key: "failed", label: "Payment failed", hint: "Sent at once, with a retry link" }, { key: "refund", label: "Refund issued", hint: "Includes the reason and amount" }, ] as const; return ( <fieldset className="grid w-full max-w-sm gap-0.5"> <legend className="mb-1 text-sm font-semibold">Email me about billing</legend> <Label htmlFor="docs-all" className="flex min-h-11 items-start gap-3 rounded-[10px] px-2 py-2.5 hover:bg-muted"> <Checkbox id="docs-all" indeterminate={count > 0 && count < 3} checked={count === 3} onChange={(event) => { const next = event.currentTarget.checked; setEvents({ paid: next, failed: next, refund: next }); }} /> <span className="grid pt-2"> <span>All billing events</span> <span className="text-[13px] font-normal text-muted-foreground">{count} of 3 selected</span> </span> </Label> {rows.map((row) => ( <Label key={row.key} htmlFor={`docs-${row.key}`} className="flex min-h-11 items-start gap-3 rounded-[10px] py-2.5 pl-8 pr-2 hover:bg-muted"> <Checkbox id={`docs-${row.key}`} checked={events[row.key]} onChange={(event) => setEvents((current) => ({ ...current, [row.key]: event.currentTarget.checked }))} /> <span className="grid pt-2"> <span>{row.label}</span> <span className="text-[13px] font-normal text-muted-foreground">{row.hint}</span> </span> </Label> ))} </fieldset> ); }
API reference #
Checkbox
component
Also accepts the native props of its root element and a ref.
PropTypeDefault
indeterminatebooleanfalse
Accessibility #
It is built on native elements and keeps aria-hidden in step with state.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.