Skip to content

The @apply Directive

The @apply directive lets you group multiple Tailwind utilities into a single custom CSS class. This lesson explains how @apply works, when it's genuinely useful, and when a UI component is the better solution instead.

What Is the @apply Directive?

@apply is a Tailwind-specific CSS directive that lets you "apply" existing utility classes inside a custom class definition, inside your CSS file. It's most useful for styling markup you don't control, like CMS output, third-party widgets, or markdown-rendered HTML.

Behind the scenes, @apply simply copies the resolved CSS declarations from each utility into your custom class at build time, so the final CSS is no different than if you'd written those properties by hand.

.btn-primary {
  @apply rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white;
}
.btn-primary:hover {
  @apply bg-blue-700;
}

Now any element with class="btn-primary" gets all four utility declarations, plus the hover state, without listing them in HTML.

@apply Directive Syntax

.custom-class {
  @apply utility-1 utility-2 utility-3;
}
  • @apply must be used inside a CSS rule, typically within an @layer components block.
  • You can apply multiple utilities in one statement, separated by spaces.
  • Responsive and state variants (hover:, md:) can be applied too, but each needs its own selector or @apply line for the base state.
  • You can mix @apply with regular CSS properties in the same rule.

@apply Directive Cheatsheet

Common patterns for grouping utilities with @apply.

Pattern Example Notes
Basic grouping @apply flex items-center gap-2; Combines multiple utilities into one class
Inside @layer @layer components { .card { @apply p-4 rounded-lg; } } Recommended way to register custom classes
Mixing with CSS @apply flex; gap: 12px; @apply can sit alongside normal declarations
Pseudo-classes .btn:hover { @apply bg-blue-700; } Apply state utilities to the matching selector
Important utility @apply !text-red-500; Keeps the !important modifier when applied
Media queries @media (min-width: 768px) { .card { @apply p-8; } } Combine with standard CSS media queries
Theme values @apply text-[theme(colors.brand)]; Reference theme values inside arbitrary utilities

When @apply Actually Makes Sense

@apply is most valuable when you can't add utility classes directly to your markup, such as content rendered from Markdown, a CMS rich-text field, or a third-party library's fixed HTML structure.

/* Styling CMS-generated markdown output you cannot add classes to */
.markdown-body h2 {
  @apply mt-8 text-2xl font-bold text-slate-900;
}
.markdown-body a {
  @apply text-blue-600 underline hover:text-blue-800;
}

@apply vs Framework Components

In component-based frameworks like React, Vue, or Astro, a reusable component is usually a better fit than @apply for buttons, cards, and other repeated UI patterns, since it also handles markup structure, props, and JavaScript behavior, not just styling.

Approach Best For Limitation
@apply class Styling markup you can't add classes to Only handles CSS, not structure or behavior
Framework component Reusable buttons, cards, form fields Requires a component-based framework
Direct utilities One-off or lightly reused markup Can get verbose if copy-pasted too often

Registering Classes With @layer

Wrapping your custom class in @layer components tells Tailwind where to inject the generated CSS in the final stylesheet, keeping the cascade order predictable relative to base styles and utilities.

@layer components {
  .badge {
    @apply inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium;
  }
  .badge-success {
    @apply bg-emerald-100 text-emerald-800;
  }
}

Utilities in @tailwind utilities still load after @layer components, so a utility class can always override a component class if needed.

Common Mistakes

  • Overusing @apply to recreate a traditional CSS-heavy workflow, defeating the purpose of utility-first styling.
  • Using @apply outside of a CSS rule or @layer block, which causes a build error.
  • Forgetting that responsive and state variants applied inside a rule only affect that rule's own selector, not automatically generating new selectors.
  • Choosing @apply for React/Vue/Astro components where a real component would be more maintainable.
  • Not wrapping custom classes in @layer components, causing unpredictable cascade order against utilities.

Key Takeaways

  • @apply lets you group multiple utility classes into one custom CSS class.
  • It's most useful for styling markup you can't directly add classes to, like CMS or Markdown output.
  • In component-based frameworks, a real component is usually better than @apply for reusable UI.
  • Wrap custom classes in @layer components to keep cascade order predictable.
  • @apply doesn't replace utility-first thinking; it's an escape hatch for specific situations.

Pro Tip

Reach for @apply only when you genuinely cannot add class names to markup. If you're building components in a JS framework, prefer extracting a real component over reaching for @apply.