SyntaxStudy
Sign Up
Tailwind CSS Extracting Components with @apply
Tailwind CSS Beginner 1 min read

Extracting Components with @apply

The @apply directive lets you compose Tailwind utilities into reusable CSS class definitions, solving the problem of duplicating long lists of utility classes across many elements. You write a semantic class name in your CSS file and use @apply to assign utilities to it. The Tailwind build process resolves all the @apply utilities at compile time, producing standard CSS with no runtime overhead. The most common use case for @apply is base component styles that appear many times in your codebase: buttons, form inputs, badges, and cards. A .btn-primary class that @applys bg-blue-600 text-white px-4 py-2 rounded-lg font-medium hover:bg-blue-700 transition-colors is far cleaner than repeating those eight classes on every button in your HTML. Variants and responsive modifiers work inside @apply just as they do inline. The Tailwind team recommends using @apply sparingly and only for genuinely repeated patterns, not as a way to avoid writing utility classes altogether. Over-relying on @apply recreates the problems of traditional CSS — you end up with a growing stylesheet of component classes, specificity battles, and styles that are harder to understand in isolation. The sweet spot is component-level abstraction in frameworks like React, Vue, or Blade rather than CSS-level abstraction via @apply.
Example
/* ── src/styles/components.css ─────────────────────── */

/* Button component extracted with @apply */
.btn {
    @apply inline-flex items-center justify-center gap-2
           px-4 py-2 rounded-lg font-medium text-sm
           transition-colors duration-200
           focus:outline-none focus:ring-2 focus:ring-offset-2;
}

.btn-primary {
    @apply btn bg-blue-600 text-white
           hover:bg-blue-700
           focus:ring-blue-500;
}

.btn-secondary {
    @apply btn bg-white text-gray-700
           border border-gray-300
           hover:bg-gray-50
           focus:ring-gray-400;
}

.btn-danger {
    @apply btn bg-red-600 text-white
           hover:bg-red-700
           focus:ring-red-500;
}

/* Form input component */
.form-input {
    @apply w-full px-3 py-2
           border border-gray-300 rounded-lg
           text-gray-900 placeholder-gray-400
           bg-white
           focus:outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-200
           disabled:opacity-50 disabled:cursor-not-allowed;
}

/* Badge variants */
.badge {
    @apply inline-flex items-center px-2.5 py-0.5
           rounded-full text-xs font-semibold;
}

.badge-blue   { @apply badge bg-blue-100   text-blue-800; }
.badge-green  { @apply badge bg-green-100  text-green-800; }
.badge-red    { @apply badge bg-red-100    text-red-800; }
.badge-yellow { @apply badge bg-yellow-100 text-yellow-800; }