Switch
A binary setting with a visible on or off position.
Preview
Use Switch for an on/off setting that applies when toggled. Keep the label stable rather than changing it from an action such as “Enable notifications” to “Disable notifications.” This demo changes local state only; it does not persist a preference.
Receive updates when a project changes.
Email notifications are off. Local preview only; no preference is saved.
Installation
pnpm dlx shadcn@latest add http://127.0.0.1:3017/r/switch.jsonInstalls Switch and its Radix primitive without changing your theme. Field, Label, and Button are separate optional items. No icon library is required. See the registry guide for local endpoints and updates.
Usage
import { Switch } from '@/components/ui/switch';
import { Field, FieldContent, FieldDescription, FieldLabel } from '@/components/ui/field';
<Field orientation="horizontal" className="gap-2">
<Switch id="notifications" checked={enabled} onCheckedChange={setEnabled}
aria-describedby="notifications-help" />
<FieldContent>
<FieldLabel htmlFor="notifications">Email notifications</FieldLabel>
<FieldDescription id="notifications-help">
Receive updates when a project changes.
</FieldDescription>
</FieldContent>
</Field>The track is 32px × 20px with a 16px thumb. Its position changes when enabled, so state is not communicated by color alone. The off track and border share the control-border color (falling back to input); the on track and border share primary. The thumb stays white in both states and both themes. Hover keeps the track and border matched. There is no shadow. Use 8px between control and label, with no added gap between the label and caption description inside FieldContent.
The track is a compact mark, not the text-control height scale. Use the label and row to provide a generous touch target. Do not shrink the thumb independently of its track.
Interaction states
These are isolated appearance specimens. Hover and focus use the same utilities as real interactions. Enabled examples remain interactive. The invalid specimen shows the border treatment only; a real invalid state needs a visible explanation.
Keyboard focus uses the shared 2px outline with a 2px offset. Disabled switches are dimmed, cannot be toggled, and are skipped by Tab. Set data-disabled on Field to dim the label too. Thumb motion respects reduced-motion preferences and follows reading direction.
Behavior and forms
Use checked with onCheckedChange for controlled state, or defaultChecked for an initial uncontrolled state. The change callback receives a boolean. For real immediate settings, persist the change, communicate pending work, and restore the previous state with an explanation if saving fails. This component does not perform those requests.
For choices that are collected and confirmed with a submit button, Checkbox is usually clearer. Use Radio Group for one choice from more than two alternatives.
Switch also supports native form participation through Radix. Set name and optionally value when using it inside a form; only an enabled checked switch contributes a value (default "on"). Reset controlled state explicitly when resetting a form. required is supported by the primitive, but a required confirmation is generally better expressed as a checkbox.
Keyboard and accessibility
- Tab focuses an enabled switch. Space or Enter toggles it.
- Clicking the associated label toggles the switch.
- Preserve
role="switch"and the checked state supplied by Radix. - Keep a visible, stable label; link supporting text with
aria-describedby. - Switch has no read-only mode. Explain unavailable settings rather than leaving a disabled switch unexplained.
- Use
aria-invalidonly when an actual validation problem exists, with a visible error outside the control. Labels remain neutral. - For right-to-left layouts, inherit or set
dir="rtl"; the thumb moves in the corresponding direction.
Right-to-left layout
This live example inherits dir="rtl". The label moves to the corresponding side and the thumb travels toward the logical end when on.
Receive updates when a project changes.
Email notifications are off. Local preview only; no preference is saved.
API
| Prop | Default | Purpose |
|---|---|---|
checked / defaultChecked | false | Controlled or initial on/off state |
onCheckedChange | — | Receives the next boolean state |
disabled | false | Prevent interaction and focus |
name / value | Value "on" | Form submission fields |
aria-invalid | Unset | Destructive border and focus treatment |
| Radix Root props | — | Includes ref, id, and accessibility attributes |