caliper uidocs

Checkbox

Free

A native checkbox with a clear checked, unchecked and indeterminate state.

Installs components/ui/checkbox.tsxDepends on none beyond ReactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/checkbox.json
Email me about billing

When 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.