Troupe tokens

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.

sm
md
lg

States

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.

Sizeuncheckedcheckedhoverfocus-visibledisabled
sm
md
lg
checkedPoint at itTab to itdisabled

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.