One Simple Trick to Cleaning Up Tailwind CSS Code
This is outdated since Tailwind CSS 3.4
Tailwind CSS can make your markup messy. However, we can prevent this by delegating classes to the parent element.
Let's take the following example.
<ul>
<li class="text-sm font-medium text-gray-900">...</li>
<li class="text-sm font-medium text-gray-900">...</li>
<li class="bg-gray-100 text-sm font-medium text-gray-900">...</li>
</ul>
We have three repeating classes on the <li>
elements.
text-sm
font-medium
text-gray-900
We can clean this up by moving these classes to the parent <ul>
element and letting the CSS cascade down.
<ul class="text-sm font-medium text-gray-900">
<li>...</li>
<li>...</li>
<li class="bg-gray-100">...</li>
</ul>
But what if we are using classes that cannot be delegated to the parent? Classes like whitespace-nowrap
, px-8
, rotate-3
and many more cannot be applied to child elements through cascading. Thankfully, there's a solution...
Enter Tailwind CSS JIT
If you're uncertain about JIT, you can refer to my blog What is JIT in Tailwind CSS? for a detailed explanation.
But here's a short description.
Since v3, JIT has been the default in Tailwind CSS and has brought a lot of power to the framework. One of the best additions is arbitrary values, these allow you to replace custom CSS with Tailwind CSS-like classes.
Let's use this example.
<ul>
<li class="whitespace-nowrap p-4 text-sm font-medium">...</li>
<li class="whitespace-nowrap p-4 text-sm font-medium">...</li>
<li class="whitespace-nowrap bg-gray-100 p-4 text-sm font-medium">...</li>
</ul>
Here we have four repeating classes.
whitespace-nowrap
p-4
text-sm
font-medium
However, only two can be delegated to the parent.
text-sm
font-medium
Here's how it would look without JIT.
<ul class="text-sm font-medium">
<li class="whitespace-nowrap p-4">...</li>
<li class="whitespace-nowrap p-4">...</li>
<li class="whitespace-nowrap bg-gray-100 p-4">...</li>
</ul>
We still have p-4
and whitespace-nowrap
repeated on all the <li>
elements.
Delegating Classes with JIT
Here's how the example looks with JIT.
<ul class="text-sm font-medium [&>*]:whitespace-nowrap [&>*]:p-4">
<li>...</li>
<li>...</li>
<li class="bg-gray-100">...</li>
</ul>
This might look confusing, but it's simple as [&>*]
is just CSS.
It's the same as writing this.
& > * {
//
}
Which translates to.
Select all first level children within this element
In our example, the &
is the <ul>
and the *
is the <li>
elements.
Here's how it would look in CSS.
ul > li {
//
}
And from that, all we're doing is applying CSS but with Tailwind CSS utilities.
ul {
@apply text-sm font-medium;
}
ul > li {
@apply whitespace-nowrap p-4;
}
Here's a more built-out example using a table component from HyperUI.
I'm unsure about this approach, as arbitrary classes have some downsides.
- Confusing to read
- Confusing to write
- Messy markup