Saltar al contenido
home / blog / tailwind-css-arquitectura
Tailwind CSS CSS Design

Design Architecture with Tailwind CSS

2026-04-18 · 6 min read
Design Architecture with Tailwind CSS

How to organize your Tailwind styles without going crazy: design tokens, reusable components and scalable patterns.

The Scaling Problem

Tailwind is incredibly productive at first. But in large projects, without a clear strategy, you end up with classes repeated in 30 places and a button with 15 inconsistently defined variants.

The solution isn’t to abandon Tailwind — it’s to give it structure.

Design Tokens as Source of Truth

Before writing a single class, define your tokens in tailwind.config.js:

// tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        brand: {
          DEFAULT: '#f97316',
          hover: '#ea580c',
          muted: 'rgb(0 255 136 / 0.1)',
        },
        surface: {
          base: '#0a0a0a',
          raised: '#111111',
          overlay: '#161616',
        },
        border: {
          subtle: '#1f1f1f',
          default: '#2a2a2a',
          strong: '#333333',
        },
      },
      fontFamily: {
        mono: ['GeistMono', 'Fira Code', 'monospace'],
      },
    },
  },
};

Now instead of bg-[#f97316] in 50 places, you use bg-brand. If the color changes, you change one place.

Components with @apply

For highly repeated elements, @apply in your CSS is a valid solution:

/* components.css */
@layer components {
  .btn-primary {
    @apply inline-flex items-center gap-2 px-5 py-2.5
           bg-brand text-black font-semibold text-sm rounded-lg
           hover:bg-brand-hover transition-colors;
  }

  .card {
    @apply rounded-xl border border-border-subtle
           bg-surface-raised/50 hover:bg-surface-raised
           transition-all duration-200;
  }
}

Use it in moderation — the goal is to extract really repeated patterns, not every button you see.

Variant Convention

Define consistent variants for interactive elements:

Base state:     text-[#888]  border-[#1f1f1f]  bg-[#111]/50
Hover state:    text-[#f0f0f0]  border-[#333]  bg-[#111]
Active state:   text-[#f97316]  border-[#f97316]/20
Disabled state: text-[#333]  cursor-not-allowed opacity-50

Documenting this in a DESIGN.md file or your Storybook prevents inconsistencies between components.

File Organization

src/
  styles/
    global.css      → @tailwind directives, @font-face, reset
    components.css  → @apply for heavily repeated patterns
  components/
    ui/
      Button.tsx    → Variants with class-variance-authority
      Card.tsx
      Badge.tsx

class-variance-authority (CVA)

For components with variants in React/Vue, CVA is superior to concatenating strings:

import { cva } from 'class-variance-authority';

const button = cva(
  'inline-flex items-center gap-2 font-semibold rounded-lg transition-colors',
  {
    variants: {
      variant: {
        primary: 'bg-[#f97316] text-black hover:bg-[#ea580c]',
        ghost: 'text-[#888] border border-[#1f1f1f] hover:text-[#f0f0f0] hover:border-[#333]',
      },
      size: {
        sm: 'text-xs px-3 py-1.5',
        md: 'text-sm px-5 py-2.5',
      },
    },
    defaultVariants: { variant: 'primary', size: 'md' },
  }
);

Conclusion

Tailwind scales well when you have well-defined tokens, clear state conventions, and extract abstractions only when there’s real repetition. The key is that design decisions live in the config, not scattered throughout the markup.