Toggle
A pill that stays pressed — the filter and mode buttons of the deck tool’s library, chart and component panels, and the site’s blog filters.
Beta · Actions · packages/css/src/components/toggle.css
.pui-toggle · --filled · --small · on = aria-pressed="true" · __icon. Labels are one or two words.
Sizes across, states down.
What it is for
Section titled “What it is for”- Two sizes: small (12px — the deck tool’s pills) and medium (14px — the site’s, and Button medium’s geometry)
- Five states: default, hover, focus, on, disabled — on is the pressed state (aria-pressed, data-state=on)
- Label is a text property; Has icon + Icon for a 16px leading glyph, off by default
- Keep labels to one or two words; a toggle that needs a sentence is a Switch with a label
Use when a filter or a mode that is on or off and shows it — a chart type, All | Charts | Images, a blog category — alone or in a Toggle group.
Do not use when it triggers an action (Button); it switches one setting in a form (Switch); it opens a view (Tabs); it is only a label (Chip).
Relates to Toggle - filled, Toggle group, Button - secondary, Chip, Tabs trigger - segment, Switch.
Anti-patterns a toggle that navigates · a lone toggle whose on-state is not visible · outline and filled toggles in one row · a toggle standing in for a Button.
Keywords: toggle, filter, pill, pressed, on, off, mode, selected, chip
Figma — page Toggle: Toggle (10 variants) · Toggle - filled (10 variants)
shadcn: toggle
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 toggle.css.
<button class="pui-toggle" aria-pressed="true">All</button><button class="pui-toggle pui-toggle--filled pui-toggle--small"><span class="pui-icon pui-toggle__icon">…</span>Charts</button>The modifiers
Section titled “The modifiers”| What it is | Note | |
|---|---|---|
| Variant | (none) outline · --filled | the two Figma sets; the registry’s variant |
| Size | --small 28 (12 px) · (none) medium 36 (14 px) | — |
| State | :hover · :focus-visible · on = [aria-pressed=“true”] or [data-state=“on”] · :disabled | — |
| Parts | __icon — a 16 px leading glyph | — |
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 | |
|---|---|---|---|---|
#544d4d on #f2f2f2 |
7.36 | 4.5 | text.muted on surface.sunken (promised) | ok |
#544d4d on #ffffff |
8.24 | 4.5 | text.muted on surface.page (promised) | ok |
#ffffff on #544d4d |
8.24 | 4.5 | Toggle label when on (promised) | ok |
#0b0202 on #ffffff |
20.51 | 4.5 | text.default on surface.page (promised) | ok |
4 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 | |
|---|---|---|---|---|---|
| Toggle | surface/page | shadow #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Toggle | surface/card | shadow #6a66e4 2 px |
#f2f2f7 |
4.06 | ok |
| Toggle | surface/sunken | shadow #6a66e4 2 px |
#f2f2f2 |
4.05 | ok |
9 of 9 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.