Button

Markup canonic · components/button.json

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

Variante

.btn .primary / .secondary / .ghost / .outline / .outline-pink · (distructiv → secțiune separată)

Disabled

orice variantă + atribut disabled · opacity 0.4 · cursor not-allowed

Mărimi

Două mărimi principale: md (40h / fs 14) default în dashboard, lg (44h / fs 16) pentru acțiuni principale (modal submit, hero CTA, formulare 1–3 câmpuri). Btn mici (sm 30h / xs 26h) sunt pill — la dimensiuni reduse, pill citește mai clar.

.lg · default (md) · .sm · .xs

Reguli

Default (md) · dashboard

40h · fs 14 · weight 600 · padding-x 24 · radius 20. Folosit în dashboard, table actions, topbar, navigation — contexte dense.

Large (lg) · acțiune principală

44h · fs 16 · weight 600 · padding-x 32 · radius 24. Folosit pe modal submit, hero CTA, formulare 1–3 câmpuri — contexte unde butonul e the acțiunea.

Small (sm) · inline

30h · fs 13 · padding-x 18 · radius pill. Filtrele din tabele, acțiuni inline, badge-uri acționabile.

Xs · micro-acțiune

26h · fs 12 · padding-x 14 · radius pill. În ticker AI, chip-uri acționabile, controls minimale.

Shadow

--sh-pink apare doar la hover pe .btn.primary. Zero shadow în starea default.

Focus states

Vizibile doar la navigare cu tastatura (:focus-visible). Color: --c-fog pe suprafețe deschise, #fff pe dark.

:focus-visible · outline 2px var(--c-fog) · offset 3px
sec-dark · outline-color: #fff

Ștergere & acțiuni distructive

Distructivul e negru și mereu cu iconiță. Butonul negru e rezervat exclusiv acestor acțiuni — nu e o variantă neutră. .btn.danger = ștergere principală (fill negru); .btn.danger.outline = acțiune distructivă cu impact mai mic (border ink). Anulările și acțiunile reversibile rămân ghost / outline / secondary, niciodată negre. Roșul (--c-error) e rezervat mesageriei de eroare, nu butoanelor.

.btn.danger (fill negru) · .btn.danger.outline (impact mic) · iconiță obligatorie

Cu iconiță & states

Button group

Rândul de acțiuni. Pe desktop orizontal, aliniat dreapta. Pe mobil vertical și full-width — un CTA înghesuit pe jumătate de ecran nu e un tap target.

Ordinea e [secundar][primar] la orice lățime — primarul la dreapta pe desktop, dedesubt pe mobil. Nu se inversează pe breakpoint.

desktop            row · gap 10px · .end aliniază dreapta
mobil (<1024px)    column · fiecare .btn width 100% · aceeași ordine
.btn-group.full    butoanele împart lățimea egal și pe desktop
.btn-group.stacked coloană la orice lățime · gap --sp-8 — vezi mai jos
.btn-group.compact excepția — vezi mai jos
Revizuit 2026-09-07. Mobilul era column-reverse, ca „primarul sus, unde ajunge degetul primul". Efectul real: o confirmare nedistructivă (pe .modal-actions) urca primarul deasupra dismiss-ului, în timp ce una distructivă (suprapusă) îl ținea dedesubt — două confirmări din aceeași aplicație, pe același telefon, în ordini inverse. Ordinea nu e o proprietate responsive.

Suprapuse · .stacked

Coloană la orice lățime, gap --sp-8, butoanele întinse de grup. Asta e forma din dialogul de dismiss și din cel de ștergere (modal): secundarul deasupra — primul focus, reduce accidentele — primarul sau distructivul dedesubt. Aceeași ordine ca rândul, alt ax.

.btn-group.stacked · max-width 360px, cât un .modal.sm

.stacked întinde butoanele el însuși, deci .btn.full e redundant în interiorul lui.

Excepția · .compact pe mobil

Două acțiuni contextuale (nu CTA-uri) pot rămâne una lângă alta pe mobil. Cere .btn.sm — la mărimea normală nu încap două pe un ecran de 380px fără să se rupă textul.

Testul: dacă acțiunea e finalul unui flow („Trimite declarația”), e CTA — vertical, full-width. Dacă e o decizie despre un element din pagină („Aprobă acest document”), e contextuală — .compact e permis.

Full-width · .btn.full

Un singur buton care ține toată lățimea containerului: CTA-ul care închide un flow și butonul din formularele mobile. Niciodată style="width:100%" — lățimea e o clasă, nu un stil inline.

.btn.primary.lg.full · un singur CTA pe ecran

Buton-icon · .icon-only

.icon-only nu e o mărime, e un modificator: compune cu scara existentă, deci un buton-icon nu poate deriva de butonul-text de lângă el. Înălțimea vine de la treaptă, aspect-ratio îl face pătrat, --r-full îl face cerc.

ClaseMărimeIconÎn aplicație
.btn.lg.icon-only44 × 4418pxsize="icon-lg"
.btn.icon-only40 × 4018pxsize="icon"
.btn.sm.icon-only30 × 3016pxsize="icon-sm"
.btn.xs.icon-only26 × 2616pxsize="icon-xs"

Mereu cu aria-label — iconul nu e numele. Pentru un control care ține o stare, nu e buton-icon, e toggle.