Joshua Wallace

Search

Engineer & Developer

Nested group modifiers in Tailwind

If you’ve been using Tailwind for even a little while, I’m sure you’ve used the group modifier at least once - or are simply aware of it. It’s exceptionally helpful modifier which allows you use to modify the styles of a child element based on the interation with the parent. The most common use case is to modify the styles when a parent is hovered, such as:

<div class="group">
    <h1>
        Title
    </h1>
    <div class="group-hover:translate-x-1 transition-transform">
        >
    </div>
</div>

This barebones example simply moves the > character to the right when the parent is hovered. You probably noticed this when clicking into this post, as this site uses it on my content cards. However, my cards have another modifier applied to them which you may have noticed as well. When you hover over the card, all the other cards slightly dim. This too uses the group modifiers, but at the list level.

<ul class="group pointer-events-none">
    <li class="group-hover:opacity-50 hover:opacity-100 transition-opacity">
        <!-- Card content -->
    </li>
</ul>

Note: The pointer-events-none modifier is applied to the list to prevent all of the children having the opacity reduced if the unordered list has a gap or spacing style applied.

This is a simple but effective, but you have noticed an issue. If I inject the prior code of the > translation into the card content, every > will be translated to the right when any card is hovered. For posterity, here is the list code with the card content provided in the slot.

<ul class="group pointer-events-none">
    <li class="group-hover:opacity-50 hover:opacity-100 transition-opacity">
        <div class="group">
            <h1>
                Title
            </h1>
            <div class="group-hover:translate-x-1 transition-transform">
                >
            </div>
        </div>
    </li>
</ul>

As you can see, we’ve defined the group twice. This means that the inner most style which depends on the group, which is the translate-x-1 style, will be using the group at the list item level - not the card.

Tailwind, of course, has a very simple and elegant solution to support multiple groups (and other modifiers). We can name the modifiers using group/name syntax. Refactoring the above example to support multiple nested groups, we get the following:

<ul class="group/list pointer-events-none">
    <li class="group-hover/list:opacity-50 hover:opacity-100 transition-opacity">
        <div class="group/card">
            <h1>
                Title
            </h1>
            <div class="group-hover/card:translate-x-1 transition-transform">
                >
            </div>
        </div>
    </li>
</ul>

With that, the modifiers are completely isolated. Now the translate-x-1 style will only be applied to the card when it is hovered, and not the list item. The list items will only have their opacity reduced when any of them are hovered except the exact one that is hovered.