Toggle

Buton-icon care ține o stare. În repaus e un cerc cu contur, gol; selectat, forma se strânge și se umple cu brand. Scara e a butonului-icon (26/30/40/44). Propunere — de validat pe un ecran real.

Markup canonic · components/toggle.json

sursa = JSON · generat de scripts/build-catalog.py

Stări

StareFormăFundalIconContrast
repaus--r-fulltransparent + contur --c-input-border-tonal--c-fogcontur 3.13:1 · icon 4.37:1
hover--r-full--c-bej-1--c-ink16.23:1
press--r-full--c-bej-1 + contur --c-input-border-hover--c-ink16.23:1
selectat--r-sm / --r-md--c-accent#fff3.67:1 — prag non-text 3:1
selectat · hover--r-sm / --r-md--c-accent-deep#fff5.39:1
dezactivatopacity: 0.4

Conturul din repaus e ce lipsea până în v8: fără el nu există vas, iar „oprit" citește ca „nu e nimic aici". Pragul non-text pentru conturul unui control e 3:1 (WCAG 1.4.11), măsurat pe fundalul real de pagină — --c-rule (0.10) dă 1.24:1 și --c-input-border (0.30) dă 2.00:1, amândouă pică. --c-input-border-tonal (0.46) dă 3.13:1.

Selectatul e --c-accent plin cu icon alb, nu --c-accent-tint cu icon deep. Alb pe accent dă 3.67:1 și trece, fiindcă un icon e non-text. Tooltipul stă la aceeași valoare ca abatere declarată, fiindcă el poartă text de 13px — nu e precedent pentru normă.

Metrici

scara         .toggle.xs 26 · .toggle 30 · .toggle.md 40 · .toggle.lg 44
icon          14px pe 26 și 30 · 18px pe 40 și 44   (ca .btn.icon-only)
repaus        jumătatea cutiei, ca lungime · contur inset 1px --c-input-border-tonal
selectat      --r-sm pe 26 și 30 · --r-md pe 40 și 44
tranziția     180ms cubic-bezier(.4,0,.2,1) pe TOT: fundal, icon, rază, contur, filter
.toggle-group carcasă pilulă cu contur · padding 3px · gap 2px · fundal transparent
activ în grup pilulă --c-accent, icon alb — FĂRĂ morph de formă

raza selectatului urcă o treaptă la 40 fiindcă morph-ul se citește ca raport
între rază și jumătatea cutiei: o rază unică ar aluneca 0.77 → 0.45, iar așa
stă în 0.77 / 0.67 / 0.70 / 0.64 — aceeași senzație pe toată scara.

raza de repaus e jumătatea cutiei scrisă ca lungime, NU --r-full: browserul taie
border-radius la jumătatea cutiei, deci de la 9999px animația e invizibilă până
în ultima jumătate de procent din durată și forma sare la final.

Solo sau grup

Solo = o stare independentă, on/off (aldin, favorit, notificări) — aria-pressed. Grup = alegere exclusivă dintr-un set mic (aliniere, densitate, interval) — role="radiogroup" + role="radio" + aria-checked, cu roving tabindex și săgeți. Dacă opțiunile se exclud și sunt peste ~4, e .select, nu un toggle group.

Regula formei: forma se schimbă doar acolo unde nu există un container care să declare setul. Solo n-are șină, deci forma ține locul ei — cercul se strânge și se umple. În grup, carcasa declară deja setul, deci itemul rămâne buton rotund în repaus și doar culoarea se schimbă. Consecința care contează: plin de brand = selectat are un singur înțeles, în ambele contexte.

În context — factură în editare

densitatea reală · două toggle solo, apoi două grupuri · roz apare DOAR unde e o stare pornită
Factură F-2026-0871 · Vodafone România S.A.

Servicii telecomunicații · septembrie 2026
Abonament business 12 linii, trafic inclus, echipamente în rate.
Bază impozabilă4.180,00 RON
TVA 21%877,80 RON

Total de plată5.057,80 RON
Scadent 2026-10-15 · SPV: transmisă 2026-09-08

Regula practică de densitate: cele două grupuri de aici sunt pragul. Toggle-ul solo își poartă conturul, deci se citește ca acțiune disponibilă; roz-ul rămâne rezervat stărilor pornite. Dacă o bară ajunge să aibă mai mult roz decât titlul documentului, accentul a încetat să mai fie accent.