Switch
A single on/off toggle — a <label> wrapping a hidden <input type="checkbox" role="switch"> with
a sliding thumb, plus an optional text label.
Installation
npm install @sipe-team/switch
import '@sipe-team/switch/styles.css';
Usage
Render a Switch and pass a label to show text beside the toggle. It works uncontrolled out of
the box — clicking the track (or its label) flips it, and the thumb slides across.
Examples
Uncontrolled
Give Switch a defaultChecked and let it track its own state — the common case for forms that read
the value on submit.
Controlled
Own the state yourself with checked and onChange when another part of the UI has to react to it.
onChange receives the native change event — read event.target.checked for the next value.
Sizes
md (default) fits most forms; sm for dense rows, lg for touch targets. The track and thumb
scale together — sm is 32×16, md 40×20, lg 48×24.
Disabled
disabled blocks interaction and dims the whole control. It applies whether the switch is on or off.
API Reference
Switch
Renders a <label> wrapping an <input type="checkbox" role="switch">. Forwards its ref to that
underlying <input>.
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'sm' | 'md' | 'lg' | 'md' | Scales the track and thumb. |
checked | boolean | — | Controlled on/off state. Pair with onChange. |
defaultChecked | boolean | false | Initial state when uncontrolled. |
onChange | ChangeEventHandler<HTMLInputElement> | — | Called with the native change event on toggle. Read event.target.checked for the next value. |
disabled | boolean | false | Blocks interaction and dims the control. |
label | string | — | Text shown beside the toggle. Also used as the accessible name when no aria-label/aria-labelledby is set. |
aria-label | string | — | Accessible name. Takes priority over label. Use it when there is no visible label. |
aria-labelledby | string | — | id of an external element that names the switch. Takes priority over label. |
onKeyDown | KeyboardEventHandler<HTMLInputElement> | — | Called on key down, after the built-in Enter-to-toggle handling. |
className | string | — | Appended to the wrapping <label> class. |
style | CSSProperties | — | Merged onto the wrapping <label> (alongside the internal size CSS variable). |
Also accepts the rest of ComponentProps<'input'> except size (name, id, required, …),
spread onto the underlying <input>.
Accessibility
- The input carries
role="switch"andaria-checkedreflects the current state, so screen readers announce it as a switch. - Accessible name resolves in priority order:
aria-label, thenaria-labelledby, thenlabel. Set one of these when the switch has no visiblelabel. - The input is a native checkbox, so
Spacetoggles it.Enteralso toggles it via a built-in handler. - Focusing the switch draws a visible focus ring around the whole control (
:focus-within).
Known limitations
- The
labeltext uses a hardcoded near-black color (color.gray900) rather than a theme-driven token, so it does not adapt to this dark-only docs site. The demos above are shown on a light card so the label stays legible; on a dark background the label text would be illegible (the toggle itself renders fine). labelaccepts astringonly, not arbitraryReactNode.