Switch

Turns a setting on or off right away.

Examples

Agent setting

Notifications

Sizes

  • defaultdefault

  • sm

States

  • off

  • on

  • hover

  • pressed

  • focus-visible

  • pending

  • invalid

  • disabled

Usage

When to use it
Use
A setting takes effect the moment it changes, with no Save button: auto-reply, retries, a spend limit.
Use
A list of independent settings, each on its own row with its label.
Not for
The choice is saved with a form's Save button. Use Checkbox.
Not for
The person picks one of two named options, like Light and Dark. Use Segmented control.
Not for
Pressing starts an action rather than changing a setting. Use Button.

Rules

8 rules
Must
Use Checkbox instead of Switch in a form with a Save button. Because a switch reads as already applied, so the person flips it and leaves without pressing Save.
Must
Set checked at once, pass pending until the save settles, and on failure set checked back and say why in a status line. Because a thumb that waits for the server stays put after the press, so the person presses again and flips it back.
Must
Wrap the switch and its label in one label element. Because a sibling span neither names the switch for a screen reader nor flips it on click, so the target is the 36px track.
Should
Name the setting in the positive, with no On or Off in it.
Never
Print On or Off beside the switch. Because a screen reader reads the word and then the checked state, and the row width shifts between On and Off.
Never
Color the on track; it stays ink. Because a colored track reads as a status, good or bad, when it only means the setting is on.
Should
Put one switch per row and split past 12 rows with a heading.
Should
Disable a switch that cannot be on and say why in text; use aria-invalid rarely.

Accessibility

6 checks
The root is role="switch" with aria-checked, named by the wrapping label.
Pending sets aria-busy and aria-readonly.
Space and Enter flip it and are ignored while pending; focus stays.
The thumb is presentational.
Forced colors draw a CanvasText border; on fills with Highlight; disabled is GrayText.
Say read-only in the row text; it has no other visual cue.

Edge cases

9 edge cases
120-character label in 320px
The label wraps and the switch keeps its size at the end of the row.
Right to left
On moves the thumb to the left, the end of the line.
Zoom 200%
The switch stays fixed px; the label grows beside it.
Slow save
The thumb stays dimmed while the save runs and further flips are ignored.
On the inverse surface
Ink and paper flip; the shape holds.
No label
Announced as switch, on, with no name.
Five clicks during a save
One flips; the rest are ignored, so one save runs.
Save never returns
Stays dimmed; the caller times it out and reverts.
Reduced motion
The thumb jumps with no transition; pending is a still 50% dim.

API

6 props
checked / defaultChecked
boolean default false
onCheckedChange
(checked, details) => void
pending
boolean
size
'sm' | 'default' default 'default'
aria-invalid
boolean default false
disabled, readOnly, name, value
Base UI

Tokens

10 tokens
--surface-page
var(--paper)
--border-control
oklch(var(--ink-c) / 0.50)
--fail-line
oklch(60% 0.236 26)
--radius-full
999px
--ink
oklch(var(--ink-c))
--paper
oklch(var(--paper-c))
--text-disabled
oklch(var(--ink-c) / 0.40)
--surface-pressed
oklch(var(--ink-c) / 0.08)
--dur-fast
120ms
--ease-step
cubic-bezier(0.2, 0, 0, 1)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.