Checkbox
A control that lets the user turn an option on or off, or pick several options from a list, with checked, unchecked and indeterminate states.
Installation
bash
npx shadcn@latest add @redpanda/checkboxbash
pnpm dlx shadcn@latest add @redpanda/checkboxbash
yarn dlx shadcn@latest add @redpanda/checkboxbash
bunx shadcn@latest add @redpanda/checkboxbash
nubx shadcn@latest add @redpanda/checkboxbash
aube dlx shadcn@latest add @redpanda/checkboxUsage
The Checkbox component provides a visually appealing checkbox with smooth animations and comprehensive accessibility support.
tsx
import { Checkbox } from "@/components/redpanda-ui/checkbox"
// Basic checkbox<Checkbox id="terms" />
// Controlled checkboxconst [checked, setChecked] = useState(false)<Checkbox id="newsletter" checked={checked} onCheckedChange={setChecked}/>
// With label<div className="flex items-center space-x-2"> <Checkbox id="terms" /> <label htmlFor="terms" className="text-sm font-medium"> Accept terms and conditions </label></div>
// Disabled checkbox<Checkbox id="disabled" disabled />
// With indeterminate state<Checkbox id="indeterminate" checked="indeterminate" />When to use
Use this decision tree to determine when to use the Checkbox component:
Use Checkbox when:
- Users need to select multiple options from a list
- Confirming agreement (terms, privacy policy)
- Enabling/disabling individual features or settings
- Creating multi-select forms
- Building data tables with row selection
- Collecting binary preferences (yes/no, on/off)
Don’t use Checkbox for:
- Single choice from multiple options (use Radio Group)
- Immediate toggle actions (use Switch)
- Navigation or triggering actions (use Button)
- Complex multi-step selections (use Multi-Select)
Anatomy
The Checkbox component is built on Base UI primitives:
plaintext
Checkbox Component Structure:┌─────────────────────────────────────────────────────┐│ <CheckboxPrimitive.Root> (Base UI primitive) ││ ┌─────────────────────────────────────────────────┐ ││ │ <button> (Interactive element) │ ││ │ │ ││ │ Styles Applied: │ ││ │ • Size (20x20px) │ ││ │ • Border (2px, changes on state) │ ││ │ • Background (transparent → filled) │ ││ │ • Focus ring (for accessibility) │ ││ │ │ ││ │ ┌─────────────────────────────────────────────┐ │ ││ │ │ <CheckboxPrimitive.Indicator> │ │ ││ │ │ ┌─────────────────────────────────────────┐ │ │ ││ │ │ │ <svg> (Checkmark icon) │ │ │ ││ │ │ │ │ │ │ ││ │ │ │ ┌─────────────────────────────────────┐ │ │ │ ││ │ │ │ │ <path> (CSS-animated path) │ │ │ │ ││ │ │ │ │ │ │ │ │ ││ │ │ │ │ Animation States: │ │ │ │ ││ │ │ │ │ • unchecked: dashoffset 1, opacity 0│ │ │ │ ││ │ │ │ │ • checked: dashoffset 0, opacity 1 │ │ │ │ ││ │ │ │ │ • Duration: 0.2s with 0.1s delay │ │ │ │ ││ │ │ │ └─────────────────────────────────────┘ │ │ │ ││ │ │ └─────────────────────────────────────────┘ │ │ ││ │ └─────────────────────────────────────────────┘ │ ││ └─────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────┘
State Management:• Controlled: Uses checked prop with onCheckedChange• Uncontrolled: Uses defaultChecked prop• Supports indeterminate state for partial selections
Accessibility Features:• Keyboard navigation (Space to toggle)• Focus management with visible focus ring• Screen reader support via Base UI primitives• ARIA attributes automatically applied• Label association through id/htmlFor
Animation System:• Pure CSS transitions (no JS animation library)• Checkmark draws in via stroke-dashoffset + opacity• 500ms color transition for state changes• Box fill leads the checkmark stroke draw-in slightlyProps
Keyboard interactions
| Key | Action |
|---|---|
Tab to the checkbox |
Focus lands on the checkbox. |
Space |
Toggles between checked / unchecked. Cycles through indeterminate when indeterminate is in use. |
Enter |
Submits the surrounding form — does not toggle the checkbox. |
Accessibility
- Renders as a real
<button role="checkbox">witharia-checked="true" | "false" | "mixed". The component also setsdata-state="checked" | "unchecked" | "indeterminate"so existing Tailwind selectors keep working. - Always pair with a visible
<Label htmlFor>; if the checkbox is inside a<Field>the label wiring is automatic. - Use
indeterminatevisually only (e.g. parent/child tree selection) — the checkbox still flips tocheckedon next toggle; don’t try to make indeterminate a persistent form value. - Group related checkboxes inside a
<fieldset>with a<legend>so screen readers announce the group context.