Tailwind: why I prefer to extract HTML components

Tailwind offers the @apply directive that you can use to extract components in your CSS by applying the styles the classes would have added.

For example:

/* Input */

.btn {
@apply inline-block rounded-3xl bg-blue-500 px-8 py-3 text-lg text-white hover:bg-blue-800 focus:bg-blue-800;
}

/* Output */

.btn {
--tw-bg-opacity: 1;
--tw-text-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
border-radius: 1.5rem;
color: rgb(255 255 255 / var(--tw-text-opacity));
display: inline-block;
font-size: 1.125rem;
line-height: 1.75rem;
padding-bottom: 0.75rem;
padding-left: 2rem;
padding-right: 2rem;
padding-top: 0.75rem;
}

.btn:hover {
--tw-bg-opacity: 1;
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
}

.btn:focus {
--tw-bg-opacity: 1;
background-color: rgb(30 64 175 / var(--tw-bg-opacity));
}

Whilst this works and reduced duplication, I prefer to handle this within my HTML instead.

All templating engines I've used have ways to loop over or map through items and including separate files such as separate partials or different components.

The main benefit of this is that you get the HTML structure of the component and not just the styling. If you extract a .btn component, it may depend on a span or other element within it to display correctly but as this isn't obvious, it may be missed when writing an implementation of it in HTML - this can't happen when working inside a loop or importing a canonical version.

Also, by working just in the HTML markup, we continue to get the lower cognitive load and speed benefits that we're used to when styling with utility classes rather than switching between multiple files.