A sliding on/off control for a setting that takes effect immediately — no separate save; semantically role="switch", with a native checkbox carrying the value and keyboard behavior. When the value is saved with a form, use a checkbox instead.
One sm/md/lg dialect. The track height drives width, thumb, and travel at a constant ~1.8:1 stretch; the default is medium.
| Example | Size | Modifier | Track | Usage |
|---|---|---|---|---|
| Small | --sm | size.icon.sm | Dense rows: table cells, compact settings lists | |
| Medium | ds-toggle | size.icon.md | The default — forms and settings panels | |
| Large | --lg | size.icon.lg | Touch targets and high-emphasis settings |
Real DOM drivers set every state; the demo class forces focus here and behaves identically. There is no hover look — the control is binary and the thumb is its affordance.
| Example | State | Driver | Roles | Usage |
|---|---|---|---|---|
| Rest, off | — | border.strong | The thumb parks left on a neutral track | |
| On | :checked | action.primary.bgsurface.page | The track carries the primary; the thumb slides right | |
| Focus | :focus-visible | focus.ring | Keyboard focus — the shared ring on the track | |
| Disabled | :disabled | action.disabled.bg | Excluded from interaction and the tab order |
A toggle commits immediately — reach for it only when there is no save step.
| Verdict | Rule |
|---|---|
| Do | Give every toggle a label — a visible one via its row, or aria-label when the surrounding text is the label; never rely on position alone. |
| Do | Keep role="switch" on the input so assistive tech announces on/off rather than checked/unchecked. |
| Don’t | Use a toggle where there is a save step — a value committed with a form is a checkbox. |
| Don’t | Use color as the only on/off signal — the thumb position carries the state. |
| Don’t | Stretch it past binary — one of several mutually exclusive options is Radio, multi-select in a form is Checkbox. |