Claude in Chrome injects a page-scoped `.hidden { display: none }` rule, breaking Tailwind `hidden md:flex` layouts

Status Open
Maintainer reply None cached
Activity 0 comments · opened Jul 28, 2026

What happens

The Claude in Chrome extension injects a page-scoped .hidden { display: none } rule into top-level pages it controls. The rule is not scoped to the extension's own UI, so it collides with any page that uses .hidden as a class name — most notably every Tailwind CSS site.

The injection is invisible to page JavaScript: it does not appear in document.styleSheets or document.adoptedStyleSheets (consistent with chrome.scripting.insertCSS), so it leaves no trace in normal DevTools/CSSOM inspection.

Minimal reproduction

Serve a page with no stylesheet at all:

<!doctype html><html><head><meta charset="utf-8"></head><body>
<div id="h" class="hidden">H</div>
<pre id="o"></pre>
<script>
  addEventListener('load', () => {
    o.textContent = 'sheets=' + document.styleSheets.length
      + ' | .hidden display=' + getComputedStyle(h).display;
  });
</script>
</body></html>

Open it in a tab the extension controls. Observed:

sheets=0 | .hidden display=none

With zero stylesheets in the document, no page CSS can produce that. Testing other class names on the same page (block, flex, sr-only, invisible, collapse) shows all of them unstyled — only .hidden is affected, confirming a single externally injected rule.

Why this is more damaging than it looks

Tailwind v4 emits every utility inside @layer utilities. In CSS, an unlayered declaration always beats a layered one regardless of specificity or source order. So the injected .hidden unconditionally overrides Tailwind's md:flex, md:block, md:grid, etc.

That means the extremely common responsive idiom

<div class="hidden md:flex">…</div>

is permanently hidden at all viewport widths while the extension is active. The same document rendered inside an iframe (which the injection does not reach) behaves correctly — 1400px → flex, 500px → none — which isolates the cause to the injected rule rather than the page's CSS.

In our app this hid both navigation sidebars and the entire content area of one screen (toolbar, filter bar and list container all used hidden md:*), leaving the app stuck on the home screen with nothing clickable. It also silently corrupts any browser-automation QA run through the extension: screenshots and computed styles reflect the injected rule, so agents can "observe" UI bugs that do not exist for real users.

Workaround

Injecting this unlayered rule restores correct behaviour without disabling anything else:

document.documentElement.appendChild(
  Object.assign(document.createElement('style'), {
    textContent: '.hidden{display:revert-layer}'
  })
);

revert-layer rolls the computed value back to the previous cascade layer, i.e. the page's own layered styles. Verified: hidden still hides, md:hidden still hides at desktop, and hidden md:flex correctly resolves to flex at ≥768px and none below.

Suggested fix

Scope the extension's CSS so it cannot match page elements — e.g. a unique prefix/namespace for extension class names, or render the extension UI in a shadow root.

Environment

  • Windows 11, Chrome (stable)
  • Reproduced on multiple sites and on a zero-stylesheet local page
  • Not reproducible inside an iframe on the same page, or in a Chrome profile without the extension

View original on GitHub ↗