Forms & input
Checkbox, Radio & Toggle
The three selection primitives, unified. Checkboxes for many-of, radios for one-of, toggles for instant on/off — shared states, sizing, and keyboard behavior, built on Base UI.
npx shadcn@latest add @orbit/checkbox @orbit/radio-group @orbit/switchWhen to use
Pick by selection logic, not by looks.
Sizes
Two sizes, matched to the rest of the form family: md 18px control (default) · sm 16px control.
States
Each kind shares the same vocabulary: unselected, selected, focus ring, disabled — plus indeterminate for checkboxes. Tab through any demo to see the 3px themed focus ring.
Groups
Common patterns: a radio group with descriptions, a checkbox group with select-all, and a toggle settings list.
Props
Checkbox
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | — | Row label. When present, the control is wrapped in a <label> so the whole row is a hit target. |
| description | ReactNode | — | Secondary line under the label. |
| size | "sm" | "md" | "md" | Control size: 16px or 18px box. |
| checked / defaultChecked | boolean | false | Controlled / uncontrolled checked state. |
| onCheckedChange | (checked, details) => void | — | Called when the checkbox is ticked or unticked. |
| indeterminate | boolean | false | Mixed state — renders the dash. Clears to a normal toggle on interaction; keep it in sync with child rows. |
| disabled | boolean | false | Blocks interaction and mutes the row. |
| …rest | Checkbox.Root props | — | Everything else (name, value, required, inputRef, …) is forwarded to Base UI Checkbox.Root, including ref. |
RadioGroup / RadioGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | — | Group: heading rendered above the options (wired via aria-labelledby). Item: row label. |
| description | ReactNode | — | Secondary line — under the group heading, or under an item's label. |
| size | "sm" | "md" | "md" | Group only. Control size, inherited by every item. |
| orientation | "vertical" | "horizontal" | "vertical" | Group only. Stack options or flow them in a row. |
| value / defaultValue | string | — | Group only. Controlled / uncontrolled selected value. |
| onValueChange | (value, details) => void | — | Group only. Called when the selection changes. |
| value (item) | string | — | Item only, required. The value this radio represents. |
| disabled | boolean | false | On the group, disables every item; on an item, just that row. |
| …rest | RadioGroup / Radio.Root props | — | Forwarded to Base UI RadioGroup and Radio.Root respectively, including ref. |
Switch
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | — | Row label. When present, the track sits on the trailing edge of the row — set w-full for a settings-row layout. |
| description | ReactNode | — | Secondary line under the label. |
| size | "sm" | "md" | "md" | Track size: 30×18 or 34×20. |
| checked / defaultChecked | boolean | false | Controlled / uncontrolled on state. |
| onCheckedChange | (checked, details) => void | — | Called when the switch flips. |
| disabled | boolean | false | Blocks interaction and mutes the row. |
| …rest | Switch.Root props | — | Everything else (name, value, required, inputRef, …) is forwarded to Base UI Switch.Root, including ref. |
Usage
Match the control to the logic
Checkbox for many-of, radio for one-of, toggle for an instant on/off setting.
Use a toggle inside a form
Toggles apply instantly; if a choice needs Save, use a checkbox instead.
Make the whole row a target
Label and control are one hit area — generous and easy to tap.
Offer a single radio
Radios need at least two choices; a lone option should be a checkbox.
Keyboard & accessibility
Base UI provides the semantics: checkbox / radio / switch roles, aria-checked (including mixed), roving focus within radio groups, and label-bound rows. The 3px focus ring uses the themed --ring token.