Skip to content

Debug overlay wrappers break CSS sibling combinators (~, +) used by Tailwind peer-* variants #1111

Description

@thomaswitt

Problem

Herb's development-mode debug overlay wraps each <%= tag.* %> ERB output in . While display: contents correctly makes these wrappers invisible to CSS layout, it does not affect the DOM tree structure. This breaks CSS sibling combinators (~, +), which operate on DOM siblings, not layout siblings.

This is particularly impactful for Tailwind CSS peer-* variants (e.g., peer-checked:, peer-focus:), which rely on the general sibling combinator (~) to style elements based on a sibling's state.

Reproduction

Minimal ERB using Rails tag.* helpers and Tailwind's Flowbite toggle pattern:

<%= tag.label(class: 'relative inline-flex cursor-pointer items-center') do %>
  <%= tag.input(type: 'checkbox', class: 'sr-only peer', checked: true) %>
  <%= tag.div(class: 'peer h-6 w-11 rounded-full bg-gray-200 peer-checked:bg-blue-600') %>
<% end %>

Expected DOM (without Herb)

<label class="relative inline-flex cursor-pointer items-center">
  <input type="checkbox" class="sr-only peer" checked>
  <div class="peer h-6 w-11 rounded-full bg-gray-200 peer-checked:bg-blue-600"></div>
</label>

input.peer:checked ~ div.peer-checked:bg-blue-600 matches → toggle shows blue.

Actual DOM (with Herb debug overlay)

<label class="relative inline-flex cursor-pointer items-center">
  <span data-herb-debug-outline-type="erb-output component" style="display: contents">
    <input type="checkbox" class="sr-only peer" checked>
  </span>
  <span data-herb-debug-outline-type="erb-output component" style="display: contents">
    <div class="peer h-6 w-11 rounded-full bg-gray-200 peer-checked:bg-blue-600"></div>
  </span>
</label>

input and div are no longer DOM siblings → CSS ~ combinator doesn't match → toggle always
appears gray/off, even when checked.

Impact

  • Visual state is lost: Checked checkboxes appear unchecked because peer-checked: never activates
  • Affects all peer-* variants: peer-focus:, peer-hover:, peer-disabled:, etc.
  • Also affects group-* variants if tag.* helpers are used (same ~ combinator pattern)
  • Adjacent sibling combinator (+) is equally affected
  • Flowbite toggle components are a common pattern that breaks completely

Workaround

Disabling Herb's debug overlay (via validation_mode: :none) resolves the issue. Production is unaffected since the overlay is development-only.

Environment

  • herb: 0.8.9
  • Ruby: 3.4.8
  • Rails: 8.1
  • Tailwind CSS: v4

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions