switch
A switch turns one setting on or off, and the change applies the moment it is flipped.
when to use
- For one setting that takes effect at once, with no save button: “Email alerts”, “Maintenance mode”.
- In a list or a panel of settings: one switch per setting, each with its own label.
when to use something else
- Inside a form that is saved with a button. Use a checkbox. A switch promises an effect at once, which the form doesn't have.
- For a choice between two things that aren't on and off, such as “daily” or “weekly”. Use a select, or tabs to change the view. A switch can only say on or off.
- To start an action, such as “deploy release”. Use a button: an action happens once, while a switch holds a state.
anatomy
- Hit area. The track, a small gap and the label: the whole target people can click or tap.
- Track. A small, wide, square frame. Off, it has a thin grey border on a dark fill; on, it is filled with blue.
- Thumb. A small square inside the track. Off, it is grey and sits at the left; on, it turns dark and slides to the right.
- Label (optional). The name of the setting, in the body face.
variants and states
A switch comes in two sizes: medium, the usual one, for lists and panels of settings, and small for dense rows and tables.
| state | looks |
|---|---|
| Off | A dark track, with a grey thumb at the left |
| On | A blue track, with a dark thumb at the right |
| Focused | An outline around the thumb, for keyboard focus only |
| Disabled | The track and the label dimmed. It can't take focus, be changed or be sent with a form |
Nothing changes under the pointer, and there is no look for an invalid value.
The change applies at once. Keep the label the same in both states, and when the effect is out of view, show it. Here, a line under the switch says what changed.
the site is open to visitors
In a settings panel, put the switches one under the other, one per setting, each with its own label.
behaviour
- A click on the label flips the switch too.
- A switch is one tab stop. space flips it; enter doesn't, as with any checkbox.
- If applying the setting can fail, set the switch back, and say why.
The full keyboard map is on the switch's React page.
accessibility
- Screen readers announce it as a switch that is on or off.
- Its label is its name. Without a visible label, give it a name that is read out but not shown. Nothing checks for one today.
- The label must not change with the state: the “on” or “off” that is announced already says it.
- If the change takes time, or shows somewhere else, confirm it with a toast or a banner. The switch only announces its own state.
Today:
- The focus outline is drawn around the thumb. On a switch that is on, the outline falls mostly on the blue track, against which its colour has a contrast of only about 1.1 to 1. Only a thin edge of it shows against the page, so keyboard focus on a switch that is on is hard to see.
- There is no invalid state. Inside a field with an error, the switch doesn't change.
- There are no styles for forced colours, the high-contrast setting some operating systems offer.
content
- Name the setting, not the action, in sentence case: “Email alerts”, “Maintenance mode”, not “Turn on email alerts”.
- Keep the label the same in both states, with no “on”, “off”, “enabled” or “disabled” in it.
- Phrase it so that on means the feature runs: “Email alerts”, not “Mute email alerts”.
- When the effect isn't obvious, say it in a hint, which a field adds: “Visitors see a maintenance notice”.
do and don't
do
don't
do
don't
do
don't
related
- Checkbox: on and off, inside a form that is saved.
- Field: adds a hint that explains the effect.
- Toast: confirms a change that happens out of view.
- Forms and settings: settings pages built from switches.
specs
| size | in code | track | thumb | the thumb slides |
|---|---|---|---|---|
| Medium | size="md" (the default) |
36 × 20px | 14px | 16px |
| Small | size="sm" |
30 × 16px | 10px | 14px |
| state | in code | looks |
|---|---|---|
| Off | The default | Track: a 1px --border-control border on --bg-2. Thumb: --fg-dim, at the left |
| On | checked, or defaultChecked |
Track: --cloud-blue fill and border. Thumb: --bg, slid to the right |
| Focused | :focus-visible, keyboard focus only |
A 2px --focus-ring outline, 2px outside the thumb |
| Disabled | disabled |
The whole switch, track and label, at 50% opacity, with a not-allowed cursor; it can't be focused, changed or submitted |
- Hit area: a
<label>around the track and the label text, 8px (--s-2) apart. - Track: square (
border-radius: 0), with 2px inner padding. Its fill and border change in 120msease. - Thumb: square. It slides in 140ms (0.14s)
ease, and its colour changes in 120ms. Underprefers-reduced-motion: reduceit moves without sliding. - Label:
label, Inter 13px, line-height 1.4, in--fg-2. - Element: a native
<input type="checkbox" role="switch">, transparent over the track. It takes the focus, the clicks and the form value; its state is the nativechecked, so don't addaria-checked. - Name without a visible label:
aria-label. Nothing enforces it today. - Focus on a switch that is on:
--focus-ringagainst--cloud-bluecontrasts about 1.1:1, and only a 1px edge of the outline shows against the page. - Not there: no hover style, no invalid look, and no
forced-colorsstyles.