f in x
> cd .. / HUB_EDITORIALE
Design, Web & Comunicazione

Reusable Tailwind Components — @apply vs Pure Components for Code That Doesn't Break

[2026-06-23] Author: Ing. Calogero Bono

Why reusable Tailwind components save you (and when they drown you)

You just finished a site with Tailwind. 700 lines of HTML. Every button is a clone of classes: px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700. Then the client asks: "change the primary color from blue to green." Your hands shake. 47 files to modify manually. That's the problem we're solving today.

We, at Meteora Web, have been using Tailwind since 2020. We've seen projects turn into maintenance nightmares because of a missing reuse strategy. And we've seen teams explode in productivity once they understood the difference between @apply and pure components. It's not a religious war: it's a technical choice that impacts your development speed and team sanity.

What @apply does and why it's not always the answer

@apply is a Tailwind directive that lets you group utility classes into a single CSS selector. Instead of writing class="px-6 py-3 bg-blue-600 text-white rounded-lg" every time, you can do:

/* styles.css */
.btn-primary {
  @apply px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition;
}

And then use class="btn-primary" in your HTML. Seems like a godsend. It works well for atomic utility classes that never change.

Sponsored Protocol

But watch out: @apply is not a component system. It's just a way to write shorter CSS. It doesn't handle state, variants (e.g., disabled, active), or composition. If you need a primary button, secondary, outline, with icon, without icon, @apply forces you to create 10 different classes. Then you end up with a huge CSS file and little flexibility.

When to use @apply? For low-level utilities that rarely change: fixed padding sizes, base colors, shadows. Never for interactive components or components that must vary by context.

Pure components: the choice that pays off long-term

By "pure components" we mean JavaScript components (React, Vue, Alpine.js) or simply HTML snippets with Tailwind classes inline managed through a template system (e.g., Laravel Blade or WordPress reusable parts).

The idea is simple: every component is a self-contained block that explicitly declares its Tailwind classes. No @apply, no extra abstractions. You repeat classes? Yes, but the advantage is that every component is instantly readable: you look at the HTML and see exactly what it does. No CSS inheritance mysteries.

Sponsored Protocol

Example with Alpine.js (works the same with Vue or React):


Notice: we didn't use @apply. Every variant is inline and conditional. The component is self-contained, testable, and changes without touching global CSS.

Why pure components scale better

  • No CSS conflicts: each component manages its own styles. No specificity wars.
  • Easy debugging: open the component, read the classes, understand everything.
  • Integrated state handling: you can use props, variables, conditionals directly in the markup.
  • Reuse without rigidity: the same base component can be configured with different props without duplicating CSS.

@apply vs pure components: how to choose in your project

It's not black and white. In many projects we use both, but with clear boundaries.

Use @apply for:

  • Base layout classes (e.g., .container-max, .section-padding)
  • Atomic utilities like .text-balance or .scroll-smooth
  • Overriding third-party components where you can't modify markup

Use pure components for:

  • Buttons, cards, forms, navbar, footer — every interactive or repeated element with variants
  • Any time you have more than 2 variants of the same component
  • Components that handle state (loading, error, empty)

The rule of thumb: if the component has more than one variant, use a pure component. If it's an invariant utility class, @apply is fine.

Sponsored Protocol

How to implement reusable Tailwind components in a real project

Let's walk through a concrete workflow using Laravel Blade (but you can adapt to any template engine).

1. Create a components folder

Place your files in resources/views/components/. Example: button.blade.php.


@props(['variant' => 'primary', 'disabled' => false])

Then use it in your HTML:

Sponsored Protocol

Save
Cancel

No @apply. Readable, extendable with $attributes to add extra classes.

2. Use Tailwind Merge for dynamic classes

The tailwind-merge package (or clsx + tailwind-merge) resolves class conflicts. Example in React:

import { twMerge } from 'tailwind-merge'

function Button({ variant = 'primary', className, children }) {
  const base = 'px-6 py-3 rounded-lg font-medium transition'
  const variants = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300'
  }
  return (
    
  )
}

Never again conflicts between external classes and internal ones.

Common mistakes (and how to avoid them)

  • @apply everywhere: you end up with a huge CSS file and no real benefit. Every change requires finding the class and updating it without seeing the HTML context.
  • Duplicated classes everywhere: if you have 50 buttons with the same classes but don't extract them into a component, refactoring is a nightmare. A pure component solves it at the root.
  • Ignoring Tailwind's inheritance: @apply doesn't solve responsive or dark mode variants. You'd still need conditional classes, making @apply less useful.
  • Not using a design token system: both @apply and pure components benefit from CSS variables for colors, spacing, fonts. Define tokens in your tailwind.config.js and then use them in classes.

What to do now

  1. Audit your current components: how many buttons, cards, forms do you have? If you repeat the same classes more than 3 times, extract a pure component.
  2. Install tailwind-merge (if using React, Vue, or Alpine with JS) or implement manual logic in templates (Blade, Twig).
  3. Create a minimal component library: start with Button, Card, Input. Test with variants. Then expand.
  4. Gradually remove @apply from all interactive components. Leave @apply only for global atomic utilities.
  5. Read the official documentation on Reusing Styles to understand the authors' perspective.

Dive deeper into everything Tailwind CSS in our main guide.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // DIGITAL AGENCY

We build the digital presence your business deserves.

Websites, social media, online advertising, e-commerce and high-performance hosting, engineered with method by computer engineers in Sciacca, for all of Italy.

> MW_JOURNAL

> READ_ALL()