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.json

Installs 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-invalid only 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

PropDefaultPurpose
checked / defaultCheckedfalseControlled or initial on/off state
onCheckedChange—Receives the next boolean state
disabledfalsePrevent interaction and focus
name / valueValue "on"Form submission fields
aria-invalidUnsetDestructive border and focus treatment
Radix Root props—Includes ref, id, and accessibility attributes

On this page