Switch
StableAn on or off setting that takes effect the moment it is flipped, such as holiday mode or a notification email. When a choice only counts once a form is sent, it is a checkbox's job instead.
Playground
Change the props, then flip the switch. Press and hold it to feel the thumb stretch.
<Switch label="Accept new orders" defaultChecked />States
Off is ink at 15%; on is Orbit teal. Disabled drops to 45% and cannot be focused. Every state at both sizes:
In both themes
On, off and disabled with labels, light and dark side by side. In dark, on turns mint.
Sizes
md is 36 by 20px with 14px label text (default). sm is 30 by 17px with 13px text, for dense panels and settings inside cards.
Label and description
label puts text to the right of the switch: it names the switch, and clicking it flips the switch too. There is no description prop, so write the description under it and link it with aria-describedby: native props go to the switch itself. Indent it by the switch's width and gap (46px, or 38px small) so it lines up with the label.
Shows shoppers a banner with the date you are back.
In a settings list
A list of switches under one heading, split by hairlines. Nothing waits for a Save button: each change is saved as it is made, and a quiet line says so.
Store notifications
Emails go to priya@harbourdesk.co.uk
An email each time an order is placed.
When a product falls to 5 or fewer in stock.
A daily summary of baskets left at checkout.
When a customer replies to an order email.
Your takings and best sellers, every Monday at 8am.
Changes save as you make them.
Controlled
Pass checked and onCheckedChange when the page needs to react to the switch, or when the value comes from the server.
Switch or checkbox?
A switch is a setting that is on or off right now. A checkbox is an answer that counts when a form is sent. If there is a Save or Submit button, the choices above it are checkboxes.
| Question | Switch | Checkbox |
|---|---|---|
| Takes effect | At once | When the form is sent |
| Reads as | A setting that is on or off | An answer or a choice to send |
| For example | Holiday mode, Accept new orders | Agree to the terms, pick products to export |
Motion
The thumb slides on the settle spring in 320ms. While it is pressed it takes the weight and stretches 4px towards the side it is about to go to (3px small). Under reduced motion it moves at once and only the colour fades.
Guidelines
- Name the setting, not the action: "Holiday mode", not "Turn on holiday mode". The switch already shows the state.
- Keep labels positive, so on means yes: "Email me about low stock", not "Do not email me".
- No "On" or "Off" text beside it; the switch says it.
- Apply the change at once and confirm it quietly. If it cannot be saved, flip it back and say why.
- When a setting needs a plan or another setting first, say so in its description rather than only disabling it.
Accessibility
- A native button with
role="switch"andaria-checked, announced as a switch that is on or off. Space and Enter flip it. - With
label, the switch and its text sit in onelabelelement, so the text names the switch. Without one, passaria-labeloraria-labelledby. - Link a description with
aria-describedby, as above. - Disabled is native: Tab skips it and its label turns quiet slate.
- The focus ring is teal, 2px, offset from the track, for keyboard focus only.
- Under reduced motion the thumb does not slide; the colour change still shows the state.
Props
Other native button attributes, and the ref, go to the switch. className goes to the outer element: the label row when there is a label.
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | None | On or off, when you control it. |
defaultChecked | boolean | false | The starting state when uncontrolled. |
onCheckedChange | (checked: boolean) => void | None | Called with the new state on every flip. |
size | 'sm' | 'md' | 'md' | 30 by 17px or 36 by 20px. |
label | ReactNode | None | Text to the right. It names the switch, and clicking it flips the switch. |
name | string | None | Form field name. The value is sent only while on. |
value | string | 'on' | Sent with the form as name=value while on. |
disabled | boolean | None | Native disabled: 45%, not focusable. |