Components
A control that allows the user to toggle between checked and not checked.
Playground
Field and FieldLabel for proper layout and labeling. The hit area extends invisibly past the 16px box, so the target stays comfortable on touch screens.import { Checkbox } from "@workspace/ui/components/checkbox"
import { Field, FieldLabel } from "@workspace/ui/components/field"
<Field orientation="horizontal">
<Checkbox id="terms" />
<FieldLabel htmlFor="terms">Accept terms and conditions</FieldLabel>
</Field>defaultChecked for uncontrolled checkboxes, or checked and onCheckedChange to control the state. The callback receives boolean | "indeterminate", so narrow it before storing a boolean.const [checked, setChecked] = React.useState(false)
<Field orientation="horizontal">
<Checkbox
id="newsletter"
checked={checked}
onCheckedChange={(value) => setChecked(value === true)}
/>
<FieldLabel htmlFor="newsletter">
{checked ? "Subscribed" : "Subscribe to the newsletter"}
</FieldLabel>
</Field>FieldContent and add a FieldDescription for helper text — the checkbox stays aligned with the first line of the label.By clicking this checkbox, you agree to the terms and conditions.
<Field orientation="horizontal">
<Checkbox id="terms-2" defaultChecked />
<FieldContent>
<FieldLabel htmlFor="terms-2">Accept terms and conditions</FieldLabel>
<FieldDescription>
By clicking this checkbox, you agree to the terms and conditions.
</FieldDescription>
</FieldContent>
</Field>aria-invalid on the checkbox and data-invalid on the field wrapper to show the invalid styles — a destructive border and ring on the box, and destructive text on the label.<Field orientation="horizontal" data-invalid>
<Checkbox id="terms-invalid" aria-invalid />
<FieldLabel htmlFor="terms-invalid">
Accept terms and conditions
</FieldLabel>
</Field>disabled prop to prevent interaction and add data-disabled to the Field so the label dims with the box. The checked state is preserved, so a disabled checkbox can stay checked.<Field orientation="horizontal" data-disabled> <Checkbox id="notifications" disabled /> <FieldLabel htmlFor="notifications">Enable notifications</FieldLabel> </Field> <Field orientation="horizontal" data-disabled> <Checkbox id="marketing" disabled defaultChecked /> <FieldLabel htmlFor="marketing">Marketing emails</FieldLabel> </Field>
FieldSet with a FieldLegend to create a checkbox list. Set variant="label" on the legend so it renders at label size.<FieldSet>
<FieldLegend variant="label">Show these items on the desktop:</FieldLegend>
<FieldDescription>
Select the items you want to show on the desktop.
</FieldDescription>
<FieldGroup className="gap-3">
<Field orientation="horizontal">
<Checkbox id="hard-disks" defaultChecked />
<FieldLabel htmlFor="hard-disks" className="font-normal">
Hard disks
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="external-disks" defaultChecked />
<FieldLabel htmlFor="external-disks" className="font-normal">
External disks
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="cds-dvds" />
<FieldLabel htmlFor="cds-dvds" className="font-normal">
CDs, DVDs, and iPods
</FieldLabel>
</Field>
<Field orientation="horizontal">
<Checkbox id="connected-servers" />
<FieldLabel htmlFor="connected-servers" className="font-normal">
Connected servers
</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>data-state="selected" on its TableRow to pick up the selected background.| Name | Role | ||
|---|---|---|---|
| Sarah Chen | sarah.chen@example.com | Admin | |
| Marcus Rodriguez | marcus.rodriguez@example.com | User | |
| Priya Patel | priya.patel@example.com | User | |
| David Kim | david.kim@example.com | Editor |
const [selected, setSelected] = React.useState<Set<string>>(new Set(["1"]))
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-8">
<Checkbox
aria-label="Select all rows"
checked={selected.size === rows.length}
onCheckedChange={(checked) => handleSelectAll(checked === true)}
/>
</TableHead>
<TableHead>Name</TableHead>
...
</TableRow>
</TableHeader>
<TableBody>
{rows.map((row) => (
<TableRow
key={row.id}
data-state={selected.has(row.id) ? "selected" : undefined}
>
<TableCell>
<Checkbox
aria-label={`Select ${row.name}`}
checked={selected.has(row.id)}
onCheckedChange={(checked) =>
handleSelectRow(row.id, checked === true)
}
/>
</TableCell>
...
</TableRow>
))}
</TableBody>
</Table>بالنقر على هذا المربع، فإنك توافق على الشروط.
<FieldGroup dir="rtl" className="gap-3">
<Field orientation="horizontal">
<Checkbox id="terms-rtl" defaultChecked />
<FieldContent>
<FieldLabel htmlFor="terms-rtl">قبول الشروط والأحكام</FieldLabel>
<FieldDescription>
بالنقر على هذا المربع، فإنك توافق على الشروط.
</FieldDescription>
</FieldContent>
</Field>
<Field orientation="horizontal">
<Checkbox id="notifications-rtl" />
<FieldLabel htmlFor="notifications-rtl">تفعيل الإشعارات</FieldLabel>
</Field>
</FieldGroup>defaultChecked or controlled via checked + onCheckedChange. Inside a form it submits value under name like a native checkbox.| Prop | Type | Default |
|---|---|---|
| checked | boolean | "indeterminate" | — |
| defaultChecked | boolean | "indeterminate" | false |
| onCheckedChange | (checked: boolean | "indeterminate") => void | — |
| disabled | boolean | — |
| required | boolean | false |
| name | string | — |
| value | string | "on" |
Tokens used
6 design tokens consumed by the Checkbox component.
--primary
Primary
--primary-foreground
Primary Foreground
--input
Input
--ring
Ring
--destructive
Destructive
--spacing
Spacing unit (4px)