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
Stări
| Stare | Formă | Fundal | Icon | Contrast |
|---|---|---|---|---|
| repaus | --r-full | transparent + contur --c-input-border-tonal | --c-fog | contur 3.13:1 · icon 4.37:1 |
| hover | --r-full | --c-bej-1 | --c-ink | 16.23:1 |
| press | --r-full | --c-bej-1 + contur --c-input-border-hover | --c-ink | 16.23:1 |
| selectat | --r-sm / --r-md | --c-accent | #fff | 3.67:1 — prag non-text 3:1 |
| selectat · hover | --r-sm / --r-md | --c-accent-deep | #fff | 5.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
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.
| Stare | Fundal | Text | Contrast |
|---|---|---|---|
| repaus | transparent (carcasa poartă conturul) | --c-ink | 16.23:1 pe bej-1 · 18.48 pe bej-0 · 19.29 pe alb |
| hover | --c-bej-1 | --c-ink | 16.23:1 |
| selectat | --c-accent | #fff | 3.67:1 — abatere declarată (prag text 4.5:1) |
| selectat · hover | --c-accent-deep | #fff | 5.39:1 — ca grupul cu iconițe |
| focus-visible | outline 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
Î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.
.input / .select | .toggle-group (30) | .toggle-group.form | |
|---|---|---|---|
| înălțime | 40 (.lg 44) | 36 = item 30 + 2 × 3 | 40 = 1 + 3 + item 32 + 3 + 1 (.lg 44, item 36) |
| fill | --c-white | transparent | --c-white |
| contur | border 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 |
| hover | conturul → 0.58 | doar itemul, bej-1 | conturul → 0.58 · itemul bej-1 |
| focus | contur fog + halo 3px | outline 2px pe item | contur fog + halo 3px pe carcasă · fără outline pe item |
| text | 14px (.lg 16) | 13px | 14px (.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
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.