Checkbox
A binary choice with a precise, legible state.
fieldform
Preview
Checkbox preview
Live · keyboard ready
One email a week, never more.
When to use
- Independent on and off choices confirmed by a submit, such as accepting terms.
- Parent rows that show a partial selection through the indeterminate state.
When not to use
- Use switch for settings that apply immediately.
- Use radio-group when only one option can be chosen.
- Use chip-group for filter facets people toggle often.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
registry.jsonjson
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "checkbox",
"type": "registry:ui",
"title": "Checkbox",
"description": "A binary choice with a precise, legible state.",
"categories": [
"inputs"
],
"dependencies": [
"@radix-ui/react-checkbox",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/components/checkbox/checkbox.tsx",
"type": "registry:component",
"target": "@components/manicat/checkbox/checkbox.tsx"
},
{
"path": "registry/components/checkbox/checkbox.module.css",
"type": "registry:component",
"target": "@components/manicat/checkbox/checkbox.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/checkbox",
"meta": {
"tier": "free",
"kind": "component",
"docs": "https://manicat.viraza.net/components/checkbox",
"markdown": "https://uiarc.dev/components/checkbox/markdown",
"tags": [
"field",
"form"
]
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
example.tsxtsx
"use client";
import { useState } from "react";
import { Checkbox } from "@/components/manicat/checkbox/checkbox";
export function CheckboxExample() {
const [checked, setChecked] = useState<boolean | "indeterminate">("indeterminate");
return (
<div className="grid gap-3">
<Checkbox
label="Email me about releases"
checked={checked === "indeterminate" ? "indeterminate" : checked}
onCheckedChange={(next) => setChecked(next === true ? true : next === "indeterminate" ? "indeterminate" : false)}
/>
<Checkbox label="Include a digest" description="One email a week, never more." />
<Checkbox label="Locked" disabled />
</div>
);
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Select all A parent checkbox that shows the indeterminate state while only some children are checked.
Select all
A parent checkbox that shows the indeterminate state while only some children are checked. preview
Live · keyboard ready
select-all-a-parent-checkbox-that-shows-the-indeterminate-state-while-only-some-children-are-checked-.tsxtsx
"use client";
import { useState } from "react";
import { Checkbox } from "@/components/manicat/checkbox/checkbox";
const permissions = ["Read", "Comment", "Edit"];
export function CheckboxSelectAllExample() {
const [selected, setSelected] = useState<string[]>(["Read"]);
const all = selected.length === permissions.length;
return (
<div className="grid w-full max-w-xs gap-3">
<Checkbox
label="All permissions"
checked={all ? true : selected.length > 0 ? "indeterminate" : false}
onCheckedChange={(next) => setSelected(next === true ? permissions : [])}
/>
<div className="grid gap-3 pl-7">
{permissions.map((permission) => (
<Checkbox
key={permission}
label={permission}
checked={selected.includes(permission)}
onCheckedChange={(next) =>
setSelected((current) => (next === true ? [...current, permission] : current.filter((entry) => entry !== permission)))
}
/>
))}
</div>
</div>
);
}
Keyboard interactions
| Keys | Action |
|---|---|
| Space | Toggles the checkbox. |
Accessibility
- Radix renders a button with role="checkbox" and aria-checked, including "mixed" for indeterminate.
- The label is a real label element tied by id; description is linked through aria-describedby.
- The drawn mark is aria-hidden.
Motion
- The fill scales in on a snappy spring while the check path draws; switching to indeterminate morphs the same path into a dash.
- Reduced motion applies every state change instantly.
Responsive behavior
- The hit box is a full control-height square, so it stays easy to tap even though the drawn box is smaller.
- The label and description wrap beside the box; the box stays top-aligned with the first line.
Performance
- A single spring on the fill and a path draw per toggle; long lists of checkboxes are fine.
Notes for AI
- Use for independent on/off choices in forms. Use switch for settings that apply immediately and chip-group for filter facets.
- Set checked="indeterminate" on a parent checkbox when only some children are selected.
- Radix renders a hidden native input when name is set, so it submits with forms.