Switch
On/off toggle. Use to flip a single immediate-effect setting — the state takes effect as soon as the user interacts, without submitting a form.
When to use
| ✅ Use when… | 🚫 Avoid when… |
|---|---|
|
Example
<Switch name="wifi" label="Wi-Fi" defaultChecked />
<Switch name="ok" label="Success" variant="success" defaultChecked />
<Switch name="bad" label="Error" variant="error" defaultChecked />
<Switch name="off" label="Disabled" disabled />Color and locked state
The on track follows the brand primary by default (same as Checkbox /
Radio); color picks another palette. A locked Switch (checked +
disabled) sits on the disabled fill with the thumb in the on position and
a muted disc — it reads quieter than an interactive on Switch, never louder.
No hover / focus depth while disabled.
<Switch name="email" label="Email confirmed" checked disabled />
<Switch name="beta" label="Beta" color="success" />Sizes
<Switch size="small" label="Small" />
<Switch size="medium" label="Medium" />
<Switch size="large" label="Large" />Label typography
When label is a string, the text uses the Design System defaults
(fontSize="small", color="neutral.180"). To adjust size, color, or weight,
pass labelProps (overrides forwarded to the internal Text/BaseText):
<Switch name="dark" label="Dark theme" labelProps={{ fontSize: 'micro', color: 'neutral.140' }} />For arbitrary markup (links, bold), pass a ReactNode as label — in that
case labelProps is ignored and the node is rendered as-is.
Interactive Demo
loading
Gotchas
nameis required when theSwitchlives inside aForm— without it, React Hook Form cannot identify the field.
Properties
Prop | Type | Default | Description |
|---|---|---|---|
color | "success" | "primary" | "secondary" | "tertiary" | "information" | "warning" | "danger" | 'primary' | Interaction palette of the checked state (fill / ring / ink). Defaults
to the brand `primary`, like `Button` and `Tabs`. `variant` (`success` /
`error`) still wins when set. |
label | ReactNode | null | Text or element shown next to the control. When a `string`, it is
rendered via `BaseText`; when a `ReactNode`, it is rendered as-is. |
labelProps | Partial<TextInterface> | — | Typography overrides for a string `label` (`fontSize`, `color`, …).
Ignored when `label` is a `ReactNode`.
@example ```tsx
<Switch name="wifi" label="Wi-Fi" labelProps={{ fontSize: 'micro', color: 'ink.secondary' }} />
``` |
onChange | ((e: ChangeEvent<HTMLInputElement, Element>) => void) | — | — |
size | "small" | "medium" | "large" | medium | Size of the control (track + thumb). |
value | string | — | — |
variant | "default" | "success" | "error" | default | Visual variant of the input — reflects the validation state. |
In addition to the props above, every component accepts the layout props (spacing, color, flex/grid, sizing, border) — not repeated here.
Theming (theme.component.switch)
The control geometry is a component token: theme.component.switch.size.{small,medium,large}, each carrying trackW / trackH / thumb / pad (px). Override one field of one size without forking the component:
createTheme({
component: {
switch: {
size: {
medium: { thumb: 20 },
},
},
},
});