Switch
An on/off switch built on a native checkbox with role="switch", wrapped in its label. The checkbox is the source of state and focus; the track and thumb are decoration. No JavaScript. Switch the brand: nothing in the component changes, only the semantic tokens behind it.
Size
Default: data-size="md", which also applies when the attribute is missing. There are no variants in v1.
smmdlgStates
The state is the native checkbox state: :checked, :hover, :focus-visible and :disabled. The ring is drawn around the track. A disabled switch keeps its position, so a checked and disabled switch still reads as on.
| Size | unchecked | checked | hover | focus-visible | disabled |
|---|---|---|---|---|---|
sm | |||||
md | |||||
lg | |||||
| checked | Point at it | Tab to it | disabled |
In a form row
The md label uses the same font size, weight and line height as the md button and field, so the text lines up. The layout (align-items, gap) belongs to the page, not to the components.
Reduced motion
The thumb slides with transform over motion.duration.state-change, but only inside @media (prefers-reduced-motion: no-preference). Under reduce the thumb changes place at once. Track and thumb colours still change with the same duration: that is feedback, not movement (ADR 0003).
Usage
<link rel="stylesheet" href="@iahola/troupe-tokens/troupe.css">
<link rel="stylesheet" href="@iahola/troupe-components/switch/styles.css">
<label class="troupe-switch" data-size="md">
<input class="troupe-switch__control" type="checkbox" role="switch" name="notifications">
<span class="troupe-switch__track" aria-hidden="true"><span class="troupe-switch__thumb"></span></span>
<span class="troupe-switch__label">Email notifications</span>
</label>Full specification: packages/components/switch/README.md.