Componente și variante
Componente în loc de @apply, variante, cn/tailwind-merge, clase dinamice.
Actualizat
Problema
Cu Tailwind, același set de clase (un buton, un card) apare de zeci de ori. Cum le refolosești fără să le copiezi peste tot? Există mai multe variante — una singură e recomandată.
| Variantă | Exemplu | Verdict |
|---|---|---|
| copy-paste | aceleași 10 clase în 30 de locuri | ✗ imposibil de schimbat |
@apply în CSS |
.btn { @apply px-4 py-2 } |
✗ reinventezi CSS clasic, pierzi avantajele |
| componentă | <Button variant="primary"> |
✓ recomandat |
| bucle / map | {items.map(i => <li className="...">)} |
✓ clasele apar o singură dată în cod |
Refolosirea = componente, nu @apply
/* ✗ reinventezi CSS clasic, pierzi avantajele */
.btn { @apply rounded-md px-4 py-2 bg-accent; }// ✓ componenta e unitatea de refolosire
export function Button(props) {
return <button className="rounded-md px-4 py-2 bg-accent text-white" {...props} />
}@apply e ok doar pentru stiluri pe care nu le controlezi prin componente (conținut din CMS, librării externe).
Variante — pattern-ul de bază
Exact ce face shared/ui/button.tsx din proiect:
const variants = {
primary: 'bg-accent text-accent-fg hover:bg-accent-hover',
secondary: 'border border-line-strong bg-surface hover:bg-hover',
ghost: 'text-muted hover:bg-hover',
}
const sizes = { sm: 'h-8 px-3', md: 'h-9 px-4' }
<button className={cn(base, variants[variant], sizes[size], className)} />Variantele sunt finite și numite — nu primești color="#f00" ca prop.
cn, clsx, tailwind-merge
clsx/ uncnsimplu — unește clase condiționat.tailwind-merge— rezolvă conflictele:twMerge('px-2', 'px-4')→'px-4'. Util când permițiclassNamedin afară care suprascrie.cva(class-variance-authority) /tailwind-variants— API declarativ pentru variante, util când ai multe combinații.
Clase dinamice — capcana
Tailwind detectează clasele citind textul fișierelor. Nu poate ghici clase construite:
`bg-${color}-500` // ✗ nu există în CSS-ul final
const colors = { red: 'bg-red-500', blue: 'bg-blue-500' }
colors[color] // ✓ clase complete, scrise literalStiluri pe date dinamice
Valori calculate la runtime → style sau variabilă CSS:
<div className="w-(--progress) bg-success" style={{ '--progress': `${pct}%` }} />Pe scurt
- Unitatea de refolosire e componenta, nu
@apply. - Variante finite, numite, într-un obiect;
cnpentru combinare,tailwind-mergepentru conflicte. - Clasele trebuie scrise complet în cod — Tailwind nu vede clase construite din bucăți.