Checkbox
A tri-state checkbox for opting in, out, or partially selecting.
Introduction
Checkboxes let people select one or more options, or confirm a single choice. Alongside checked and unchecked, they support an indeterminate state for parent options whose children are partially selected. Built on Radix UI's Checkbox primitive, so keyboard interaction and ARIA state are handled for you.
Installation
npx shadcn@latest add https://indiacn.in/r/checkbox.jsonimport { Checkbox } from '@/components/ui/checkbox';Usage
<div className="flex items-center gap-3">
<Checkbox id="terms" defaultChecked />
<Label htmlFor="terms">Accept terms and conditions</Label>
</div>Examples
Default
import { useCallback, useState } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Body3 } from '@/components/ui/typography';
export default function Component() {
return (
<div className='flex items-center gap-3'>
<Checkbox id='terms' defaultChecked />
<Label htmlFor='terms'>Accept terms and conditions</Label>
</div>
);
}States
All three types across enabled and disabled.
import { useCallback, useState } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Body3 } from '@/components/ui/typography';
export default function Component() {
return (
<div className='grid gap-4'>
<div className='flex items-center gap-3'>
<Checkbox id='state-checked' defaultChecked />
<Label htmlFor='state-checked'>Checked</Label>
</div>
<div className='flex items-center gap-3'>
<Checkbox id='state-indeterminate' checked='indeterminate' />
<Label htmlFor='state-indeterminate'>Indeterminate</Label>
</div>
<div className='flex items-center gap-3'>
<Checkbox id='state-unchecked' />
<Label htmlFor='state-unchecked'>Unchecked</Label>
</div>
<div className='flex items-center gap-3'>
<Checkbox id='state-disabled' disabled defaultChecked />
<Label htmlFor='state-disabled'>Disabled</Label>
</div>
</div>
);
}Controlled Group
1 document selected
import { useCallback, useState } from 'react';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Body3 } from '@/components/ui/typography';
const DOCUMENTS = ['Aadhaar', 'PAN card', 'Driving licence'];
interface IDocumentOptionProps {
document: string;
checked: boolean;
onToggle: (document: string) => void;
}
/** Single checkbox row within the controlled group example. */
function DocumentOption({ document, checked, onToggle }: IDocumentOptionProps) {
const handleCheckedChange = useCallback(() => onToggle(document), [document, onToggle]);
return (
<div className='flex items-center gap-3'>
<Checkbox id={document} checked={checked} onCheckedChange={handleCheckedChange} />
<Label htmlFor={document}>{document}</Label>
</div>
);
}
export default function Component() {
const [selected, setSelected] = useState<string[]>(['Aadhaar']);
const handleToggle = useCallback((document: string) => {
setSelected((current) =>
current.includes(document)
? current.filter((entry) => entry !== document)
: [...current, document],
);
}, []);
return (
<div className='grid gap-3'>
{DOCUMENTS.map((document) => (
<DocumentOption
key={document}
document={document}
checked={selected.includes(document)}
onToggle={handleToggle}
/>
))}
<Body3 className='text-neutral-500'>
{selected.length} document{selected.length === 1 ? '' : 's'} selected
</Body3>
</div>
);
}Accessibility
- Toggles with Space and is reachable with Tab.
- Pair every checkbox with a
LabelwhosehtmlFormatches the checkboxid, so the label is a click target and is announced by screen readers. - The focus ring is
4pxat 48% primary, which clears WCAG AA against both themes.
API Reference
Checkbox
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | 'indeterminate' | — | Controlled state. Pass 'indeterminate' for a partial selection |
defaultChecked | boolean | false | Initial state when uncontrolled |
onCheckedChange | (checked: boolean | 'indeterminate') => void | — | Fires when the state changes |
disabled | boolean | false | Prevents interaction and dims to 38% |
required | boolean | false | Marks the field as required in a form |
name | string | — | Name submitted with the parent form |
value | string | 'on' | Value submitted when checked |
className | string | — | Extra Tailwind classes |