Switch
Switch — a setting that takes effect at once, on or off.
Beta · Forms · packages/css/src/components/switch.css
.pui-switch · --small · __input __track __label. The label names the setting, the switch shows its state.
Sizes across, states down.
What it is for
Section titled “What it is for”- Size: small, medium
- Checked: false, true
- Four states by design: default, hover, focus, disabled — a switch has neither a pressed nor an error state. Hover darkens the track (border/strong off, action/primary/bg-hover on); focus is border/focus with the 3px ring at 15%; disabled is opacity 0.5
- Label is a text property and can be hidden (Has label) in a table row where the column is the label — the Cabinet’s ReportTable uses it that way
Use when turning a setting on or off with immediate effect — no submit, no confirmation.
Do not use when the change needs a Save (Checkbox in a form); the choice is between two named options (Toggle group); an action is being triggered (Button).
Relates to Checkbox, Toggle group, Field (a switch row with a description on a settings page — Field’s horizontal orientation, later).
Anti-patterns a switch that needs a Save · a label that changes with the state (“Enabled” / “Disabled”) — the label names the setting, the switch shows its state · an unlabelled switch outside a table · a switch on a destructive setting without confirmation.
Keywords: switch, toggle, on off, setting, enable
Figma — page Checkbox, Radio & Switch: Switch (16 variants)
shadcn: switch
The markup — copy this
Section titled “The markup — copy this”The class, the parts, and nothing that is not in the package. The same block opens switch.css.
<label class="pui-switch"> <input class="pui-switch__input pui-sr-only" type="checkbox" role="switch"> <span class="pui-switch__track"></span> <span class="pui-switch__label">Email me a weekly report</span></label>The modifiers
Section titled “The modifiers”| What it is | Note | |
|---|---|---|
| Size | (none) medium 32 × 18 · --small 24 × 14 | — |
| Button | a switch that is one <button role=“switch” aria-checked>: the button carries __track itself and shows its state by aria-checked / data-state=“checked”. | — |
Rule — the label names the setting; the switch shows its state — never “Enabled” / “Disabled”.
Accessibility — measured, not assumed
Section titled “Accessibility — measured, not assumed”Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.
Contrast
Section titled “Contrast”| ink on ground | reads | floor | the matrix calls it | |
|---|---|---|---|---|
#0b0202 on #ffffff |
20.51 | 4.5 | text.default on surface.page (promised) | ok |
1 distinct pair(s) rendered, 0 that axe calls a violation.
The focus ring
Section titled “The focus ring”| primitive | on | the indicator | over | the change | |
|---|---|---|---|---|---|
| Switch | surface/page | shadow #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Switch | surface/card | shadow #6a66e4 2 px |
#f2f2f7 |
4.06 | ok |
| Switch | surface/sunken | shadow #6a66e4 2 px |
#f2f2f2 |
4.05 | ok |
4 of 4 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.
Keyboard
Section titled “Keyboard”Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.
Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.