Quick word of warning with complex Tailwindcss classes: check your escaping.
I wasn’t able to change my HTML for a section of an app I was working on, but I wanted the toggle button to change when a sidebar contained content:
<div>
<div>
<a href="/"
turbo-frame="sidebar"
class="blue-or-red-if-sidebar-is-filled">
Load stuff
</a>
</div>
<turbo-frame id="my_sidebar">
<div>stuff</div>
</turbo-frame>
</div>
The selector I ended up using looked something like this:
bg-blue-500 [body:has(#my\_sidebar_div)_&]:bg-red-500
Let’s build this up:
[body:has(#my_sidebar div)]
: a custom selector that uses the :has()
pseudo-class to target the body
containing a #my_sidebar
with a div
inside it.#my\_sidebar
: The \
escapes the underscore in #my_sidebar div
, which is necessary because Tailwind treats _
as a space._div
: The underscore is needed here because we want Tailwind to treat it as a space._&
: Targets the current page element.But here’s the twist: in raw HTML this worked fine. In Rails/ERB, I had this:
<%= link_to "Load stuff",
"#",
class: "bg-blue-500 [body:has(#my\_sidebar_div)_&]:bg-red-500" %>
That single \
makes Tailwind happy, but Ruby wouldn’t create the right class string, I needed to double escape it. But I couldn’t use \\
because Tailwind wouldn’t see the right class any more 🤦🏻♂️
The fix is simple once you know it: use single quotes.
<%= link_to "Load stuff",
"#",
class: 'bg-blue-500 [body:has(#my\_sidebar_div)_&]:bg-red-500' %>
Ruby doesn’t mess with the backslash in single-quoted strings, and Tailwind can now do its thing properly.