Tailwind CSS and BEM

— 4 minute read

I have been experimenting with Tailwind CSS and trying to find an approach which fits my development workflow and approach to writing HTML and CSS.

Tailwind is a “utility-first CSS framework for rapidly building custom designs”. It provides a config driven set of classes that can be applied directly in to your HTML. Their documentation provides a good overview of traditional approach vs using utility classes;

<button class="bg-blue-500 text-white font-bold font-xl my-2 py-2 px-4 rounded max-w-md">
Button
</button>

<button class="bg-green-500 text-white font-bold font-sm my-2 py-1 px-2 rounded max-w-sm">
Button
</button>

Even in this simple example you probably think this HTML is becoming unwieldy and this is a light example of the classes you might apply to a single element. Colleagues I have shared these snippets with have raised concerns about the approach.

If you have a table listing with two buttons on each row, for example “view” and “edit”, and 10 rows, the HTML soon grows exponentially*. And if you have buttons throughout the page, each one will need to be updated manually if something changes.**

Personally, I don't find this approaching to writing HTML and CSS appealing. There are definitely benefits to this approach, including rapid development (matching their strapline). However, once you have built out a few pages, you soon see a lot of duplication.


Using BEM permalink

You can combine Tailwind’s config-driven, decent presets and the opinionated naming conventions with approaches to writing reusable components and maintainable HTML. A lot of people (including me!) seem to have missed the section in the Tailwind documentation which helps you achieve this.

I am a fan of the Block Element Modifier (BEM) methodology and Tailwind can easily be used with this approach.

Firstly, you define your component;

<button class="button">
Button
</button>

<button class="button button--primary button--small">
Button
</button>

Then, you can use @apply to use the Tailwind utilities directly in your SCSS.

@tailwind base;

.button {
@apply text-white font-bold font-xl my-2 py-2 px-4 rounded max-w-md;
@apply bg-blue-500;

&--primary {
@apply bg-green-500;
}

&--small {
@apply font-sm py-1 px-2 max-w-sm;
}
}

The Tailwind documentation on Extracting Components has a section on using @apply in this way. In their examples, they include the @tailwind components; and @tailwind utilities; but if you don't plan on using the utilities and stick strictly to the BEM component methodology you don't need to include them.

I am a big fan of Tailwind, with the flexibility config and opinionated naming conventions but not of the HTML use many people first see and stick with. If you're the same, I hope this primer on using Tailwind with BEM methodology shows the benefits of the approach and how you can achieve this with your projects.


* Gzipping helps reduce the HTTP payload (due to the repetitive nature of the classes).

** There are approaches with componentising everything, but this can be a step to far for smaller projects and adds another burden on the developer and workflow.