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). În grup, itemii pot purta și un cod scurt în loc de icon — .toggle-group.text. Printre câmpuri, .form le dă mărimea și conturul inputului.

Markup canonic · components/toggle.json

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

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
dezactivat—opacity: 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 (solo)  .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
mărime grup   pe carcasă: 30px implicit · .form 40 / .form.lg 44 printre câmpuri
              .xs/.md/.lg doar pe toggle-ul solo
.form         fill alb · border 1px --c-input-border · --r-lg · hover/focus ale câmpului
              .tonal = .input.tonal · item 32 (.lg 36) · text 14 (.lg 16)
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 — excepția sunt codurile scurte din .toggle-group.text, până la 12, pe un rând.

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.

Grup cu text scurt · .toggle-group.text

Pentru coduri și acronime de câteva caractere — D300, D394, TVA, CAS — în loc de iconițe. Același grup (radiogroup, roving tabindex, carcasa cu contur o dată) și aceeași regulă a formei: în grup se schimbă doar culoarea. Înălțimea e treapta toggle-ului; lățimea îmbracă textul.

treapta implicită, 30px — printre câmpuri, .form · hover sau focus pe un cod arată numele complet
StareFundalTextContrast
repaustransparent (carcasa poartă conturul)--c-ink16.23:1 pe bej-1 · 18.48 pe bej-0 · 19.29 pe alb
hover--c-bej-1--c-ink16.23:1
selectat--c-accent#fff3.67:1 — abatere declarată (prag text 4.5:1)
selectat · hover--c-accent-deep#fff5.39:1 — ca grupul cu iconițe
focus-visibleoutline 2px --c-fog, offset 3px + bula cu numele——

Selectatul e brandul, ca la iconițe. Alb pe --c-accent dă 3.67:1; ca text de 13px e sub pragul de 4.5:1. E o abatere declarată, decizia ownerului DS (2026-10-14): alb pe brand pink e suficient perceptual, deci selectatul nu trece pe --c-accent-deep — aceeași excepție ca tooltipul. Repausul e --c-ink, nu --c-fog ca la icon: fog ca text trece doar pe alb (4.56) și pică pe bej-0 (4.37) și bej-1 (3.84).

Cifre tabulare, nu mono. D300 și D301 au aceeași lățime, deci codurile stau aliniate și un item nu-și mută vecinii; un font mono ar aduce a doua familie într-un rând de controale Inter.

Numele complet. Un acronim nu e nume accesibil: fiecare item are aria-label="D300 — Decont de TVA", cu codul primul (WCAG 2.5.3). Bula de la hover / focus citește același attr(aria-label), deci ce se aude și ce se vede nu pot diverge — fără title, fără markup de tooltip per item.

cap            max 12 itemi, toți pe UN rând — fără wrap, fără scroll orizontal
mărimea        a grupului: 30px · .form 40 / .lg 44 printre câmpuri — fără .xs / .md / .lg pe itemi
eticheta       un cod de ≤ 5 caractere (D300, D394, TVA, CASS); un cuvânt → .tabs / .select
nu încape      containerul e mai îngust decât grupul (mobil, panou lateral) → .select
„toate"        dacă filtrul are nevoie de el, e primul item și intră în cap
ordinea        a domeniului (familia TVA împreună), fixă — nu alfabetică, nu după frecvență live
fără amestec   icon și text nu stau în același grup

În context — Vertigo · Declarații

11 coduri pe un rând — D301 e la un click, nu la trei (tab → dropdown → opțiune) · în aplicație grupul stă lângă „Depuse"; coloana docului e prea îngustă pentru amândouă, deci aici ia rândul de dedesubt — grupul însuși nu se rupe niciodată

Înainte: „De depus / Depuse" + un dropdown de declarații — trei click-uri până la D301. Cu codurile pe un rând, filtrul e la vedere și la un click. Cele 11 coduri măsoară 627px la treapta implicită (un cod de 4 caractere = 54.7px); peste 12, sau într-un container în care grupul nu mai încape pe un rând, alegerea e .select.

Printre câmpuri · .toggle.form · .toggle-group.form

Toggle-ul obișnuit e al barelor: transparent, deci conturul lui duce singur limita — 0.46, desenat cu inset box-shadow, iar grupul are 36px. Lângă un .input (40px, alb, border 0.30) se citește ca altă familie. .form îi dă contractul câmpului: aceeași înălțime, același fill, același contur, același hover și focus.

fără .form — grupul de 30 lângă un input: 36px, transparent, contur 0.46 · cu .form — 40px, alb, conturul inputului
Fără .form
Cu .form
pe card bej-1 — câmpuri albe, deci .form alb · grupul și toggle-ul solo (clopoțelul) au conturul, fill-ul și înălțimea inputului
Cota TVA
pe card alb — câmpuri .tonal, deci .form.tonal: fill bej-0, contur 0.46, exact ca .input.tonal
Cota TVA
.lg — lângă .input.lg / .select.lg: formulare sub 1024px și modale · 44px, item 36, text 16px
Cota TVA
.input / .select.toggle-group (30).toggle-group.form
înălțime40 (.lg 44)36 = item 30 + 2 × 340 = 1 + 3 + item 32 + 3 + 1 (.lg 44, item 36)
fill--c-whitetransparent--c-white
conturborder 1px --c-input-border (0.30)inset box-shadow --c-input-border-tonal (0.46)border 1px --c-input-border (0.30)
.tonal--c-bej-0 + 0.46—--c-bej-0 + 0.46
hoverconturul → 0.58doar itemul, bej-1conturul → 0.58 · itemul bej-1
focuscontur fog + halo 3pxoutline 2px pe itemcontur fog + halo 3px pe carcasă · fără outline pe item
text14px (.lg 16)13px14px (.lg 16)

Contrastul conturului. 0.30 dă 2.00:1 pe bej-0, sub pragul de 3:1 pe care îl respectă toggle-ul transparent. .form îl ia odată cu fill-ul inputului: e ținut la contractul câmpului de lângă el. Fără fill, conturul e iar singura limită — și atunci e toggle-ul obișnuit, cu 0.46.

Unde nu. În bare, antete de card și .tbl-filters containerul există deja; vasul alb de 40px ar desena a doua cutie în el. Acolo grupul e cel de 30.

Î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.