Toggle
<button class="toggle" type="button" aria-pressed="true" aria-label="Bold"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M6 4h8a4 4 0 0 1 0 8H6zM6 12h9a4 4 0 0 1 0 8H6z"></path> </svg></button>
<button class="toggle" type="button" aria-pressed="false" aria-label="Italic"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M19 4h-9M14 20H5M15 4 9 20"></path> </svg></button><button class="toggle" type="button" aria-pressed="false" aria-label="Bold">…</button>aria-pressed is both the state and the styling hook, so flipping the attribute is the whole
update — there is no second class to keep in sync. A <button> that carries the attribute is
flipped for you on click, because nothing in the platform does it: a pressed button holds its own
state, unlike a checkbox.
| Attribute | Meaning |
|---|---|
aria-pressed | The state, and what the styling reads |
data-pk-controlled | Leave the state alone — you set aria-pressed yourself |
data-value | Carried in the change event |
Each press fires pk:toggle:change on the button:
document.addEventListener("pk:toggle:change", (event) => { console.log(event.detail.pressed, event.detail.value);});Variants
Section titled “Variants”<button class="toggle" type="button" aria-pressed="false">Default</button><button class="toggle toggle-outline" type="button" aria-pressed="false">Outline</button><button class="toggle" type="button" aria-pressed="true">Pressed</button><button class="toggle" type="button" disabled>Disabled</button><button class="toggle toggle-sm" type="button" aria-pressed="false">Small</button><button class="toggle" type="button" aria-pressed="false">Default</button><button class="toggle toggle-lg" type="button" aria-pressed="false">Large</button>In a form
Section titled “In a form”A toolbar toggle is a button, but a toggle that submits a value is a checkbox. Wrap one in the
label and the styling follows :checked instead of aria-pressed.
<label class="toggle toggle-outline"> <input class="sr-only" type="checkbox" name="notify" value="email" checked /> Email</label>
<label class="toggle toggle-outline"> <input class="sr-only" type="checkbox" name="notify" value="sms" /> SMS</label><label class="toggle toggle-outline"> <input class="sr-only" type="checkbox" name="notify" value="email" /> Email</label>Toggle or Switch?
Section titled “Toggle or Switch?”A toggle is a button that stays pressed — bold, italic, a filter that is on. A switch is a setting. If it reads as “on/off” rather than “pressed/not pressed”, it is a switch.
Set dir="rtl" on the page or on any subtree — icon padding follows the reading direction. See
the button page for a live example.
Accessibility
Section titled “Accessibility”- An icon-only toggle needs a name:
aria-label, or.sr-onlytext inside it. - The name says what it controls, not its state. “Bold”, not “Bold is on” —
aria-pressedalready announces the state. - Do not swap the icon to convey state. A play icon becoming a pause icon is ambiguous; keep
the icon and let
aria-pressedcarry the change. - The checkbox form keeps the input focusable.
.sr-onlyhides it visually without taking it out of the tab order, whichdisplay: nonewould.