Checkbox
A checkbox whose tick draws itself, with an indeterminate state.
$
pnpm dlx shadcn@latest add https://lodeui.com/r/checkbox.jsoncomponents/examples/checkbox-demo.tsx
"use client";
import * as React from "react";
import { Checkbox } from "@/components/ui/checkbox";
const tasks = ["Write release notes", "Update screenshots", "Tag v2.4.0", "Post in #launches"];
export default function CheckboxDemo() {
const [done, setDone] = React.useState<string[]>([tasks[0]]);
const all = done.length === tasks.length;
return (
<div className="w-full max-w-xs rounded-xl border border-border bg-card p-4">
<label className="flex items-center gap-3 border-b border-border pb-3 text-sm font-medium">
<Checkbox checked={all ? true : done.length ? "indeterminate" : false} onCheckedChange={() => setDone(all ? [] : tasks)} aria-label="Select all" />
Launch checklist
<span className="ml-auto text-xs font-normal text-muted-foreground">{done.length}/{tasks.length}</span>
</label>
<ul className="space-y-2.5 pt-3">
{tasks.map((t) => (
<li key={t}>
<label className="flex items-center gap-3 text-sm">
<Checkbox checked={done.includes(t)} onCheckedChange={(c) => setDone((d) => (c ? [...d, t] : d.filter((x) => x !== t)))} aria-label={t} />
<span className={done.includes(t) ? "text-muted-foreground line-through" : ""}>{t}</span>
</label>
</li>
))}
</ul>
</div>
);
}When to use
- Independent on/off choices in a form that apply on submit.
- Selecting rows, with an indeterminate 'select all'.
When not to use
- Settings that apply instantly: use a switch.
- One choice from several: use a radio group.
Installation
$
pnpm dlx shadcn@latest add https://lodeui.com/r/checkbox.json1Install the dependencies
npm install motion2Copy the source into your project
components/ui/checkbox.tsx"use client"; import * as React from "react"; import { motion } from "motion/react"; import { cn } from "@/lib/utils"; export interface CheckboxProps { checked?: boolean | "indeterminate"; defaultChecked?: boolean; onCheckedChange?: (checked: boolean) => void; disabled?: boolean; id?: string; className?: string; "aria-label"?: string; } export function Checkbox({ checked, defaultChecked = false, onCheckedChange, disabled, id, className, ...aria }: CheckboxProps) { const [internal, setInternal] = React.useState(defaultChecked); const state = checked ?? internal; const on = state === true; const mixed = state === "indeterminate"; return ( <button type="button" role="checkbox" id={id} aria-checked={mixed ? "mixed" : on} aria-label={aria["aria-label"]} disabled={disabled} onClick={() => { const next = !on; if (checked === undefined) setInternal(next); onCheckedChange?.(next); }} className={cn( "grid size-[18px] shrink-0 place-items-center rounded-[5px] border outline-none transition-colors duration-150", "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:opacity-40", on || mixed ? "border-primary bg-primary text-primary-foreground" : "border-input bg-transparent hover:border-foreground/40", className, )} > <svg viewBox="0 0 16 16" fill="none" className="size-3" aria-hidden> <motion.path d={mixed ? "M4 8h8" : "M3.5 8.5l3 3 6-7"} stroke="currentColor" strokeWidth={2.2} strokeLinecap="round" strokeLinejoin="round" initial={false} animate={{ pathLength: on || mixed ? 1 : 0, opacity: on || mixed ? 1 : 0 }} transition={{ duration: 0.22, ease: [0.2, 0.8, 0.2, 1] }} /> </svg> </button> ); }
Usage
Import it from @/components/ui/checkbox after installing.
example.tsx
import * as React from "react";
import { Checkbox } from "@/components/ui/checkbox";
export function Terms() {
const [ok, setOk] = React.useState(false);
return (
<label className="flex items-center gap-2 text-sm">
<Checkbox checked={ok} onCheckedChange={setOk} aria-label="Accept terms" /> I accept the terms
</label>
);
}API reference
Checkbox
A checkbox whose tick draws itself, with a mixed state.
| Prop | Type | Default | Description |
|---|---|---|---|
| checked / defaultChecked | boolean | "indeterminate" | – | Controlled state; indeterminate shows a dash. |
| onCheckedChange | (checked: boolean) => void | – | Called on toggle. |
| disabled | boolean | – | Dims and blocks interaction. |
Keyboard interactions
| Keys | Action |
|---|---|
| Space | Toggle |
Accessibility
- role="checkbox" with aria-checked true, false or mixed.
Motion
- The check path draws in with pathLength (220ms).
Responsive behavior
- 18px square; place it in a label for a larger tap target.
Performance
- One SVG path.
Notes for AI
- Wrap in <label> so clicking the text toggles it.
This page as Markdown, for assistants and coding agents:
/components/checkbox/markdownThe full library index for assistants is at /llms.txt.
Lode222 doc pagesllms.txt