Switch
Turns a setting on or off right away.
Examples
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 / defaultCheckedbooleandefaultfalseonCheckedChange(checked, details) => voidpendingbooleansize'sm' | 'default'default'default'aria-invalidbooleandefaultfalsedisabled, readOnly, name, valueBase 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)