You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Style elements across nested layouts with Tailwind
Tailwind has this really useful group utility, that I recently discovered is super useful in frameworks with nested layouts.
You can use group to style any element based on any other element in the DOM. This may not seem like a big deal, but consider this example where we can hide the header if there's an element with the hide-header-signal class somewhere in the DOM.
This uses the named groupgroup/body to uniquely identify the group, in case we add more groups later.
You might think that you could just conditionally render the header to achieve the same thing, but that's not always easy to do, especially in frameworks with nested layouts and streaming responses, like Next.js.
Here's a real world example: This blog has a header on all pages, so the header can simply be in the root layout. But I also have two pages for visual regression testing of my syntax highlighting and markdown rendering, and I don't want to show the header on those pages, because the tests shouldn't fail when I change the header.
You don't have access to the current URL in the root layout, in order to conditionally hide the header based on the URL, unless you make the layout a client component – because of partial rendering and streaming.
You could also move the header into every page instead of the layout, and not include it in the pages where you don't want to show the header, but then you don't take advantage of your layouts.
You could create more nested folders with nested layouts, but you do it just for those two pages.
So although you could do a bunch of things to render the header dynamically for those pages, it has a comparatively high impact on our codebase. Sometimes this impact is justified and one of these approaches might be a better choice, but clearly not in this case where I just have some unlisted pages for testing purposes.
By using the pattern above, with our group utility friend, it's now super easy to hide the header on some pages:
// layout.tsxexportdefaultfunctionRootLayout({ children }){return(<html><bodyclassName="group/body"><headerclassName="group-has-[.hide-header-signal]/body:hidden"><Header/></header>{children}</body></html>)}// e.g. regular blog post pages// posts/[...slug]/page.tsxexportdefaultfunctionPage(){return(<main><p>The header is visible on this page</p></main>)}// e.g. pages for visual regression testing// vrt/[...name]/page.tsxexportdefaultfunctionPage(){return(<main><p>The header is hidden on this page</p><divclassName="hide-header-signal"/></main>)}
Done. A simple change which just added a few classes and affected 2 files, instead of changing a lot of code and affecting many files.
This example is only using the has-[.hide-header-signal] modifier, but it's not limited to only this modifier. You can do even more than to simply hide one element based on the existence of another element. For example, you could change the position of an element based on the data attribute of another element. Or change colors of the navigation – you know, sometimes websites are generally in light mode but then have some special pages where it's suddenly dark mode.
And the nice thing is: it's just CSS.
I guess these selectors are slow as hell, but get your shit together, browsers.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Style elements across nested layouts with Tailwind
Tailwind has this really useful
group
utility, that I recently discovered is super useful in frameworks with nested layouts.You can use
group
to style any element based on any other element in the DOM. This may not seem like a big deal, but consider this example where we can hide the header if there's an element with thehide-header-signal
class somewhere in the DOM.This uses the named group
group/body
to uniquely identify the group, in case we add more groups later.You might think that you could just conditionally render the header to achieve the same thing, but that's not always easy to do, especially in frameworks with nested layouts and streaming responses, like Next.js.
Here's a real world example: This blog has a header on all pages, so the header can simply be in the root layout. But I also have two pages for visual regression testing of my syntax highlighting and markdown rendering, and I don't want to show the header on those pages, because the tests shouldn't fail when I change the header.
So although you could do a bunch of things to render the header dynamically for those pages, it has a comparatively high impact on our codebase. Sometimes this impact is justified and one of these approaches might be a better choice, but clearly not in this case where I just have some unlisted pages for testing purposes.
By using the pattern above, with our
group
utility friend, it's now super easy to hide the header on some pages:Done. A simple change which just added a few classes and affected 2 files, instead of changing a lot of code and affecting many files.
This example is only using the
has-[.hide-header-signal]
modifier, but it's not limited to only this modifier. You can do even more than to simply hide one element based on the existence of another element. For example, you could change the position of an element based on the data attribute of another element. Or change colors of the navigation – you know, sometimes websites are generally in light mode but then have some special pages where it's suddenly dark mode.And the nice thing is: it's just CSS.
I guess these selectors are slow as hell, but get your shit together, browsers.
Beta Was this translation helpful? Give feedback.
All reactions