Switch
A switch flips a setting that takes effect immediately; use a
Checkbox for something that is submitted later. It is
Headless UI's Switch (a <button role="switch"> with a hidden input for
forms) drawn as a track and thumb. With label or description it wraps
itself in a Headless UI Field, so clicking the label toggles it and the
description lands in aria-describedby.
import Switch from '@zuilib/primitives/switch'
Basic
checked + onCheckedChange for controlled, defaultChecked for
uncontrolled. onCheckedChange receives the boolean, not an event.
Sizes and label position
Track, thumb and thumb travel scale with --spacing (h-4 w-7, h-5 w-9,
h-6 w-11); the text beside it is text-sm for sm and md,
text-base for lg. labelPosition="start" puts the text first, which
suits a settings list where the toggles line up on the right.
Invalid
invalid sets aria-invalid, paints the track border --danger and
turns the keyboard ring the danger colour.
In a Field
Without label / description only the track renders, so it picks up the
enclosing Field's Label, FieldDescription and FieldError.
invalid defaults to the field's invalid, and disabled (left
undefined) inherits from the Field / Fieldset.
Props
SwitchProps extends Headless UI SwitchProps (minus as, children)
with:
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | — | Controlled state; use defaultChecked for uncontrolled |
defaultChecked | boolean | false | |
onCheckedChange | (checked: boolean) => void | — | |
label | ReactNode | — | Visible label; wraps the control in a Field so clicking it toggles |
description | ReactNode | — | Helper text wired through aria-describedby |
labelPosition | 'end' | 'start' | 'end' | Where the label and description sit relative to the track |
size | 'sm' | 'md' | 'lg' | 'md' | |
invalid | boolean | Field invalid | aria-invalid, data-invalid, danger border and ring |
disabled | boolean | Field / Fieldset disabled | Leave unset to inherit; an explicit false overrides the context |
name | string | — | Native form participation via a hidden input |
value | string | 'on' | Submitted value when on |
id | string | — | Replaces the Field-generated id; the label's htmlFor follows it |
className | string | — | Merged last onto the track (the element ref points at) |
Slots
| Slot | Element | Notes |
|---|---|---|
[data-slot="switch"] | button | The track, role="switch". Headless UI sets data-checked, data-hover, data-focus, data-disabled; ZUI adds data-invalid |
[data-slot="switch-thumb"] | span | The knob; aria-hidden, slides on data-checked |
[data-slot="switch-field"] | div | Present with label / description: the Headless UI Field |
[data-slot="switch-text"] | div | Column holding label and description |
[data-slot="switch-label"] | label | — |
[data-slot="switch-description"] | p | — |
/* Consumer CSS: a success-coloured "on" track */
[data-slot="switch"][data-checked] {
background-color: var(--success);
}
Tokens
| Token | Used for |
|---|---|
--spacing | Track, thumb and travel per size |
--muted, --muted-foreground | Off track and its hover |
--primary | On track |
--background, --shadow-2 | The thumb |
--danger | Invalid border and ring |
--ring | Keyboard focus ring |
--duration-normal | Track colour and thumb travel |
--text-sm, --text-base | Label and description |
Accessibility
- The track is a
<button role="switch">witharia-checked; a hidden input carriesname/valueto the form. - Space and Enter toggle; Tab moves through switches in document order.
- With
labelthe<label>is associated to the track through the Field, so clicking the label toggles it. Pass the sameidon the control when you set one; the label'shtmlForfollows it. descriptionand aField'sFieldDescription/FieldErrorare joined intoaria-describedby.invalidsetsaria-invalid; keyboard focus shows the shared--ringring (focus-visibleonly), danger-coloured when invalid.disabledsetsdata-disabledandaria-disabled, dims the track and label and showscursor-not-allowed.- Thumb travel and track colour transitions are off under
prefers-reduced-motion.
Related
- Checkbox: the same anatomy for a value submitted later.
- Radio group: one of many.
- Field, Label, FieldError: the field wiring.