Tailwind CSS in Production · Theming and Consistency
The Dropdown Behind the Header
A user menu opened behind the next section no matter how high its z-index went, because a parent created a new stacking context.
Scenario
Example team: a page header uses backdrop-blur for a frosted-glass effect. Inside it, an account dropdown has z-50. Below the header, a hero section has relative z-10.
What you see in production
The dropdown opens behind the hero. Someone changes it to z-[9999]. It still opens behind.
The naive code
<header class="relative backdrop-blur"> <!-- creates a stacking context, z-index auto -> treated as 0 -->
<div class="absolute z-[9999]">Menu</div>
</header>
<section class="relative z-10">Hero</section>
Reproduce it
<div class="grid gap-6 p-6 sm:grid-cols-2">
<div>
<div class="relative h-12 rounded-t-lg bg-sky-200/70 p-3 text-sm backdrop-blur">Header (no z-index)
<div class="absolute top-8 left-3 z-50 w-40 rounded-lg bg-white p-3 shadow-lg ring-1 ring-gray-200">Menu z-50</div>
</div>
<div class="relative z-10 h-24 rounded-b-lg bg-rose-300 p-3 text-sm">Hero z-10 covers the menu</div>
</div>
<div>
<div class="relative z-20 h-12 rounded-t-lg bg-sky-200/70 p-3 text-sm backdrop-blur">Header z-20
<div class="absolute top-8 left-3 z-50 w-40 rounded-lg bg-white p-3 shadow-lg ring-1 ring-gray-200">Menu z-50</div>
</div>
<div class="relative z-10 h-24 rounded-b-lg bg-rose-300 p-3 text-sm">Hero z-10 stays below</div>
</div>
</div>
Root cause
z-index only compares elements within the same stacking context. backdrop-filter, filter, transform, opacity < 1, isolation: isolate and positioned elements with a z-index all create a new one. The menu's z-50 is "50 inside the header", and the header as a whole sits below the hero.
The fix
- Give the parent that creates the context a z-index above its siblings (
z-20on the header). - Render floating UI (menus, dialogs, toasts) in a portal at the end of
<body>, or use the nativepopoverattribute /<dialog>which draw in the top layer. - Define a small z-index scale in your theme (
--z-dropdown,--z-modal) instead of escalating numbers; useisolatedeliberately on components.
Trade-offs
- Portals detach DOM from component structure; handle focus and positioning (Floating UI) carefully.
- The top layer (
popover,<dialog>) needs modern browsers; it's supported in current ones.
Detect it in production
- Visual tests that open each menu and dialog on pages with blurred or transformed sections.
Key points
- z-index works within stacking contexts; blur, transforms and opacity create them.
- Fix the parent's level or move floating UI to a portal or the top layer.
Practice questions
A dropdown with z-50 appears behind a sibling section with z-10. Why?
Answer
The dropdown is inside a parent that creates a stacking context (for example with backdrop-blur, transform or opacity) and that parent sits below the section. z-index only compares elements within the same context; raise the parent or render the dropdown in a portal or the top layer.
Open in the app to mark lessons complete, take notes and track your progress.