@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
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.
@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.
<!-- 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.
@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