Jonathan Bennett

The Backslash That Ruined My Day

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

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.