Switch
StableTurns a setting on or off, taking effect the moment it's flipped.
Anatomy
- 1TrackBrand-filled when on, neutral when off. Its hit area extends invisibly to 44×36px.
- 2ThumbSlides across on a spring when toggled, and stretches while pressed.
- 3LabelNames the setting, not the action. Clicking it toggles the switch too.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/switch.jsonUsage
import { Field, FieldLabel } from "@/components/ui/field"
import { Switch } from "@/components/ui/switch"<Field orientation="horizontal">
<Switch id="auto-deploy" />
<FieldLabel htmlFor="auto-deploy">Deploy on every push</FieldLabel>
</Field>The thumb travels on a spring and stretches while pressed, the way a physical toggle gives under your finger. With reduced motion it simply snaps into place.
Examples
Switch or checkbox?
A switch is a light switch: flipping it changes something immediately — no Save button, no confirmation. A checkbox is a form answer: nothing happens until the form is submitted. Here the switch restyles the card the instant it changes.
Settings list
The most common home for switches: one setting per row, the label and a short description on the left, the switch on the right where the eye lands after reading. Separators keep long lists scannable.
Let reviewers leave comments on preview deployments.
Keep clients on the version they loaded until they refresh.
Anyone with the link can read build output.
Sizes
size="sm" fits dense tables and compact panels; the default size suits forms and settings pages.
States
Disabled switches keep their position so people can still read the current value. When a setting is required, mark the switch aria-invalid and explain why in a FieldError.
Guidelines
When to use
- For settings that apply immediately: notifications, integrations, feature toggles, dark mode.
- For binary states people understand without extra explanation — on or off.
When not to use
- In forms that are submitted — use a Checkbox.
- For choices that aren't on/off, such as Monthly vs Yearly — use a Radio Group or Toggle Group.
- For actions with consequences that need confirmation — use a Button and an Alert Dialog.
Labels
Label the setting, not the state. The switch already shows on and off, so the label should name what is being turned on — never Enable / Disable, and never text that changes when the switch flips.
Email notifications
Notifications are on — click to turn off
Feedback
Because a switch acts immediately, confirm the result when it isn't visible on screen — a Toast such as Preview comments enabled — and undo the change (with an explanation) if the request fails.
Accessibility
The switch renders role="switch" with aria-checked, plus a hidden checkbox input for forms. A sibling FieldLabel with htmlFor both names it and toggles it on click.
| Key | Behavior |
|---|---|
Tab | Moves focus to the switch. Focus shows a 2px ring offset from the track. |
SpaceEnter | Toggles the switch. |
- Boundaries. The off track uses the
inputtoken, which meets 3:1 against the page (WCAG 1.4.11); the on track uses the brand solid. The thumb's position — not color alone — carries the state. - Target size. The 36×20px track has a transparent hit area extending it to 44×36px.
- Motion. The spring and stretch are removed under
prefers-reduced-motion.
API reference
Switch
Renders a <span role="switch"> with a thumb and a hidden <input type="checkbox">. Accepts every prop of Base UI's Switch.Root.