Switch

Turns one setting on or off, and the change takes effect at once. Black when on, in two sizes, with an optional label that toggles it too. Built on the vendored Base UI switch.

Playground

Switch
State

Sizes

md by default; sm for dense rows such as a table of services. Both reach past their edges for a comfortable hit area, and on a touch screen that hit area meets the 40px touch floor while the track keeps its size.

States

Off is an ink tint, on is black; the white thumb casts a soft shadow, with no outline. Disabled dims the switch and ignores presses.

With a label

label wraps the switch in a real <label>: clicking the text toggles it, and the text names it. Put the label after the switch inline, or before it with labelPosition="start".

Settings rows

Label first, switch at the far edge: stretch the label with className — with a label, it lays out the label, so the whole row is the target.

Named from elsewhere

In a table row the name is already on screen: give the switch an aria-label that says which row it belongs to. Where a separate label sits apart from it, point the label's htmlFor at the switch's id.

Skin fade45 min · €25
Beard trim20 min · €15
Hot towel shave30 min · €22

API reference

PropTypeDefaultDescription
checkedboolean—Controlled state. Pair with onCheckedChange.
defaultCheckedbooleanfalseInitial state when uncontrolled.
onCheckedChange(checked: boolean, details) => void—Called with the new state on every toggle.
size"sm" | "md""md"18px tall by default; 14px for dense rows. On a touch screen either one's hit area is 40px tall.
labelReactNode—Visible text in a wrapping <label>: clicking it toggles, and it names the switch.
labelPosition"end" | "start""end"Label after the switch (inline) or before it (settings rows). Needs label.
disabledbooleanfalseIgnores presses and dims the switch; a label's text goes muted.
namestring—Submits with a form: "on" when checked, nothing when off (override with value / uncheckedValue).
idstring—Lands on the hidden input, so a <label htmlFor> elsewhere names and toggles the switch.
aria-labelstring—The name when there's no visible label — say which row it belongs to.
classNamestring—Layout for the outermost element: the label when there is one, else the switch.

Everything else passes through to the Base UI switch (readOnly, required, inputRef, …).

Guidelines

  • A switch acts the moment it flips — online booking goes live, a service stops being bookable. If the change waits for a Save button, it is a form choice: use a RadioGroup instead.
  • Label the setting, not the action: “Online booking”, not “Enable online booking”. The switch already says on or off — never add “On”/“Off” text beside it.
  • Every switch has a name: label, a label pointing at its id, or an aria-label that names the row (“Active: Skin fade”), not just the column.
  • Use md everywhere people tap; keep sm for dense tables where the switch sits beside other data.
  • Disable a switch only when it truly can't change, and say why nearby — “Connect payments to take deposits”.