Apply a style to a children with Tailwind
By Flavio Copes
How to style all child elements in Tailwind CSS 4 with the *: variant, reach every descendant with **:, or use the older [&>*] arbitrary variant.
To style all the direct children of an element in Tailwind CSS 4, use the *: variant. It arrived in Tailwind 3.4. Before that you wrote the [&>*] arbitrary variant, which still works and spells out exactly what’s going on.
It doesn’t happen often, but sometimes I wonder, how do I apply a style to a child element, with Tailwind?
The next time this happens, I’ll have this blog post explain it to me.
The arbitrary variant
This is the older, explicit form. It’s more typing, but it shows you the CSS selector, so let’s start here.
You can use this class name to apply the bg-gray-300 class (for example) to all child elements of the current element:
[&>*]:bg-gray-300
Like this:
<ul class="[&>*]:bg-gray-300">
<li>Astro</li>
<li>HTMX</li>
<li>Alpine.js</li>
</ul>
How does it work? Inside the square brackets you write a CSS selector. The & stands for the current element, and > * is the CSS child combinator, which matches every direct child. Tailwind generates the equivalent of this CSS:
ul > * {
background-color: #d1d5db;
}
Every li gets the gray background, and you only wrote one class on the parent. Handy when the children come from a loop, or from markdown you don’t control.
The *: variant
The *: variant is the shorthand for this exact need:
<ul class="*:bg-gray-300">
<li>Astro</li>
<li>HTMX</li>
<li>Alpine.js</li>
</ul>
Same result, less typing. This is the one to use in a Tailwind 4 project. If you’re starting one from scratch, here’s how to set up Tailwind CSS with Vite.
Direct children only
Both variants target direct children. Grandchildren are not affected. If you need to reach all descendants, Tailwind 4 has the **: variant:
**:bg-gray-300
It works like *:, but it matches every element nested inside, at any depth. It gets really handy when you pair it with another variant to narrow things down, like **:data-avatar:rounded-full to round every element with a data-avatar attribute, however deep it sits.
The arbitrary version uses an underscore instead of >:
[&_*]:bg-gray-300
In arbitrary variants, the underscore stands for a space. So this generates the descendant selector, which matches every element nested inside, at any depth.
One thing to watch out for
You can’t override the style from the child. Say one li needs a white background, so you add bg-white to it. It won’t win against the parent’s *:bg-gray-300, because of how the generated child selector is applied. Tailwind’s docs call this out too.
The fix: when children need different styles, skip the child variant and put the classes on each child directly. The child variant is for the case where all children get the same treatment.
Want me to talk about your product? You can sponsor this site.