A modal or dropdown hides behind other content despite a huge z-index
“A dropdown with z-index: 9999 renders under a card next to it, a modal appears behind the sticky header, or a menu is cut off at the edge of a scroll container.”
THE PRINCIPLE
An element can never stack above its stacking-context ancestor's siblings, and a transformed or filtered ancestor becomes the containing block even for position: fixed. Overlays belong in the top layer or at the document root.
FIRST MOVES
- In DevTools, walk up from the overlay and note each ancestor that creates a stacking context (transform, opacity < 1, filter, will-change, position fixed/sticky, isolation, contain, z-index on positioned or flex/grid items).
- Check for overflow: hidden, auto, or clip on an ancestor; it clips absolutely positioned descendants whose containing block is inside it.
- If position: fixed is offset or clipped, look for an ancestor with transform, filter, backdrop-filter, or contain: it became the containing block.
- Move modals to <dialog>.showModal() and menus or tooltips to the popover attribute: both render in the top layer, above every stacking context and outside ancestor clipping.
- Where the top layer does not fit, portal the overlay to the end of <body> and keep a small, named z-index scale for the rest.
TOOLS: THEN → NOW
Escalating z-index values (999, 9999, 2147483647)Top layer via <dialog> and the Popover API, plus a documented z-index scale
Portals plus JavaScript positioning (Popper, Floating UI)Still valid; CSS anchor positioning can replace the JS where your browser support matrix allows
PATTERN SNAPSHOT
<button popovertarget="account-menu">Account</button>
<!-- Top layer: unaffected by ancestor z-index, transform, or overflow. -->
<div id="account-menu" popover>
<a href="/settings">Settings</a>
<button popovertarget="account-menu" popovertargetaction="hide">Close</button>
</div>
<style>
/* For the rest of the page: isolate components so their z-index stays local. */
.card { isolation: isolate; }
:root { --z-sticky: 10; --z-toast: 20; }
</style>CLOSE THE AI. EXPLAIN THIS.
A child with z-index: 100 renders below a sibling of its parent that has z-index: 2. What has to be true about the parent, and what are two ways out?HOW IT WORKS UNDERNEATH
RELATED SYMPTOMS
SOURCES
Guide reviewed