Docs
Switch

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…
  • Turning an immediate-effect preference on/off (Wi-Fi, notifications, dark theme).
  • Settings panels where each row controls an independent boolean.
  • Selecting multiple items in a form submitted later — use Checkbox.
  • Exclusive choice among a few options — use Radio.
  • An action that triggers a flow (save, send) — use Button.

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

  • name is required when the Switch lives inside a Form — 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 },
      },
    },
  },
});

See also

  • Storybook story: Components / Switch
  • Multiple selection: Checkbox
  • Exclusive choice: Radio