How and When To Use @apply in Tailwind

JD LienJD Lien
7 min read

If you've used CSS for long, you're likely used to creating CSS components for reusable styles. A big drawback of Tailwind appears to be code duplication — imagine having to add in all the classes for a button hundreds of times in an application: background colors, font colors, padding, margins, borders, and all the variants for hover, active, focus and so on. It would be maddening.

Behold @apply, Our Savior!   Maybe.

Fortunately, Tailwind gives us a tool for this: @apply. This allows us to use existing Tailwind (and custom) classes and create CSS components of our own.

Here's a button class I've used:

@tailwind base;
@tailwind components;
@tailwind utilities;

.btn {
        @apply inline-flex items-center justify-center
            rounded
            border-x border-t border-b
            border-x-zinc-300/70 border-t-zinc-100 border-b-zinc-400/80
            bg-gradient-to-b from-zinc-200 to-zinc-300
            px-2 py-1
            shadow
            hover:text-opacity-100
            focus:outline-none
            focus:ring-2
            focus:ring-blue-400/50
            focus:ring-offset-0
            focus:ring-offset-transparent
            active:-translate-y-px
            disabled:text-opacity-100
            disabled:opacity-60
            disabled:active:translate-y-0;
}

That's a lot of classes for a single element that is repeated many times. In this case, I have just applied the Tailwind classes and created my own component so I can simply use a class of .btn on anything that should be styled like a button.

You can even @apply .btn in another selector if you wanted, making @apply even more powerful. Imagine an inactive button that should look disabled, without disabling it, so it can still trigger an error message.

.btn-inactive {
   @apply btn opacity-60;
}

Wait... Do You You Really Want to @apply  All the Things?

@apply sounds really helpful — you can clean up all those messy classes cluttering up your HTML. But you should carefully weigh whether you actually need to create your own CSS component classes. After all, the whole point of Tailwind is that it gives you an easy, well-documented way to use a utility-first approach to designing CSS.

I have discussed the pros and cons of using Tailwind and its utility-first approach in another article, but to summarize, there are big advantages for maintainability by using Tailwind such as:

  • No thinking of class names
  • Less switching between CSS and front-end code
  • Easily making style changes
  • Ease of maintenance

If you begin to use @apply all over the place, you've obviated all of those benefits where you've used them.

  • You now have to think of names for your new components.
  • You have to agree on those names with other developers and remember them when you need that style.
  • Overriding these styles can become difficult if you need something a bit different.
  • Developers won't immediately understand what the class does, and must look up your class and figure out what it's for and where it's used if it needs changing.

For these reasons, you ought to think twice before reaching for @apply; the majority of the time, there are better solutions. Here is a guide on when to use @apply.

Are You Using A Component-Based Framework?

If your frontend code uses components, it makes sense to use this feature in lieu of @apply. This way, you get to leverage the power and maintainability of utility-first design and combine that with the maintenance benefits and DRY-ness of extracting commonly used bits of code to components.

Components can even work for simple, single-elements like buttons or links, as you could have props or parameters you pass to give different styles and behaviours of buttons re-use a lot of code. But this is particularly true when you have more complicated components, like forms, tables, modals, etc. — this way you can combine your structural HTML with the style so that they are in one place that you go to make updates. That means that you can also build in the logic to make multiple variants. For example, you could have a "size" attribute that allows you to have large, medium, or small buttons.

See the following simplified example VueJS component: a radio button styled as a slider toggle.

<!-- An input with a few size options -->
<template>
  <div class="flex items-start">
    <span
      class="relative inline-flex"
      :class="{'h-4 w-8': size === 'sm', 'h-6 w-12': size === 'md', 'h-8 w-16': size === 'lg'}"
    >
      <input
        :class="{'h-4 w-8': size === 'sm', 'h-6 w-12': size === 'md', 'h-8 w-16': size === 'lg'}"
        class="peer absolute cursor-pointer rounded-full border-0 !bg-none outline-none checked:border-0 bg-zinc-300"
        v-bind="$attrs"
        type="checkbox"
      />

      <label
        :for="id"
        aria-hidden="true"
        :class="{'h-3 w-3 top-0.5 left-0.5 peer-checked:translate-x-4': size === 'sm', 'h-5 w-5 peer-checked:translate-x-6': size === 'md', 'h-7 w-7 peer-checked:translate-x-8': size === 'lg'}"
        class="absolute top-0.5 left-0.5 transform cursor-pointer rounded-full bg-white shadow ring-0 duration-200"
      >
      </label>
    </span>
  </div>
</template>

<script>
export default {
  props: {
    size: {
      type: String,
      default: 'md',
    },
  },
}
</script>

We could have made a CSS component for the checkbox, but as this Vue component has a few HTML elements, and since my project uses it many times over, it makes sense to create a component. At this point, there will be no repetition of the used styles, so using @apply wouldn't make sense. Additionally, we can use Vue conditional classes to tweak several styles based on a specified size.

There would be many drawbacks and few advantages to @applying styles here. We can apply similar concepts to Laravel Blade components, React components, Angular, etc.

Are You Using a Server-Side Language?

If you're not using a frontend framework like this (or Laravel), but you're just using vanilla PHP in a simple project, you could do similar extractions of components using PHP includes and such.

Are The Classes Actually Repeated in Many Places?

In many cases, we think that we are repeating a lot of exact Tailwind classes in a lot of places, but it often turns out that either

  1. There are subtle differences in many cases between instances of this "repeated" class
  2. All of the repetition occurs in one place.

If there are differences, then herein lies the benefit of Tailwind - if there were differences between them, you might have to fight against a CSS component to get the changes you are looking for. In this case @apply isn't your friend.

Further, if the repetition occurs in one place or in a single file, you can use multi-cursor editing to select and edit all instances of this at once — this isn't particularly more difficult or time consuming than going back to a separate CSS file and editing a class then coming back. If you don't understand how to use multi-cursor editing, selecting several words at once, or selecting several lines at once in your IDE, you should definitely learn this. Let me know if you'd like a tutorial on this if you have no idea what I'm talking about!

Here's a perfect example of where multi cursor editing could allow you to adjust all these <img> elements with only a few keystrokes:

  <div class="mt-3 flex -space-x-2 overflow-hidden">
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.25&w=256&h=256&q=80" alt=""/>
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
    <img class="inline-block h-12 w-12 rounded-full ring-2 ring-white" src="https://images.unsplash.com/photo-1517365830460-955ce3ccd263?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""/>
  </div>
  <div class="mt-3 text-sm font-medium">
    <a href="#" class="text-blue-500">+ 198 others</a>
  </div>

In reality, most the "duplication of styles" isn't in your source code, the output of it that the browser receives. In the source code it lives as, loops in your backend or frontend code. So the apparent duplication is of little or no concern when it comes to maintaining your source code. So in these scenarios, it's not worth using @apply. You may think that this could at least reduce the payload to the browser, but in reality this sort or repetitive output compresses well and the actual difference to user experience is almost unmeasurable and thus isn't worth the maintenance burden it will incur.

Are Your Repeated Classes Causing You Maintainability Problems Right Now?

At the end of the day, if you aren't solving a problem with @apply, then you're probably creating problems for no reason. If your code is fine the way it is and isn't actually more work to maintain, you're best leaving it and saving the extra weight and complexity in your application by avoiding creating extra classes you don't really need.

Okay, You're Really Sure You Want To Use @apply!

If you're not using a framework with components, you're not using a server-side language, you're mainly just creating a style for a single-element, that element is widely reused in exactly the same form over and over, and you're struggling with maintainability problems — then you can use @apply in good conscience. This is what it's for.

As a review, see this flowchart Tweeted by Adam Wathan, the creator of TailwindCSS.

Should_you_Use_Apply.jpg

I hope you found this article interesting. For more content like this, follow me on Twitter!

0
Subscribe to my newsletter

Read articles from JD Lien directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

JD Lien
JD Lien

I have been developing websites professionally since 1999 and have used a number of technologies and watched the evolution of the web since its early days. I write about PHP, Laravel, Tailwind, and topics about improving your career as a developer.