@apply and Extracting Component Classes

Fold repeated utility combos into a single class β€” and know when NOT to.

Sometimes the same string of utilities repeats on markup you cannot componentize — output from a Markdown renderer, a CMS, or a third-party widget. For those cases, @apply lets you bake utilities into a real CSS class.

How it reads

@layer components {
  .btn {
    @apply inline-flex items-center gap-2 rounded-lg
           px-4 py-2 font-medium transition;
  }
  .btn-primary {
    @apply btn bg-cyan-500 text-white hover:bg-cyan-600;
  }
}

Now class="btn-primary" carries all of it. Because it lives in @layer components, later utilities still win, so you can override with class="btn-primary px-8".

The honest warning

It is tempting to @apply everything and feel like you have “clean” HTML again. Resist. That road leads you straight back to the naming-things, two-files-open world Tailwind freed you from — now with an extra indirection layer.

  • Good use: markup you do not author (prose, embeds).
  • Good use: a tiny, truly-global primitive like .btn.
  • Better still: a template component/partial — the framework, not CSS, owns reuse.

In v4, @utility is often the sharper tool because the result is automatically variant-aware. More on that later in this chapter.

Example

Try it yourself
Loading editor…
Press Run to see the result.

When to use it

  • A developer extracts a ten-class badge pattern into .badge-success using @apply so dozens of template files each become one class.
  • A content author's prose is automatically styled without touching class lists by wrapping CMS output in an @apply-based .prose-content class.
  • A team avoids @apply for one-off components, using it only for truly repeated patterns to prevent the stylesheet from growing unnecessarily.

More examples

Alert component via @apply

@apply collapses ten utility classes into .alert-warning, so any future style change is made in one CSS file rather than every template.

Example Β· css
@layer components {
  .alert-warning {
    @apply flex items-start gap-3
           bg-yellow-50 border border-yellow-300
           text-yellow-800 text-sm
           rounded p-4;
  }
}

When NOT to use @apply

One-time utility combinations should stay in the markup; @apply is only worth the indirection when the same set appears in multiple places.

Example Β· html
<!-- Bad: @apply for a one-time element creates dead code in CSS -->
<!-- .hero-title { @apply text-5xl font-black text-white; } -->

<!-- Good: keep one-off utilities in the template -->
<h1 class="text-5xl font-black text-white">Hero Headline</h1>

Component with state utilities

A base .btn class holds shared layout utilities; .btn-primary extends it by also applying it with @apply, keeping the variant hierarchy DRY.

Example Β· css
@layer components {
  .btn {
    @apply inline-flex items-center gap-2 px-4 py-2
           text-sm font-medium rounded-lg
           transition duration-150;
  }
  .btn-primary {
    @apply btn bg-indigo-600 text-white
           hover:bg-indigo-700
           focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2;
  }
}

Discussion

  • Be the first to comment on this lesson.
@apply and Extracting Component Classes β€” Tailwind CSS | SoundsCode