Modal behind overlay problems usually happen when the overlay has a higher z-index than the modal, the modal is trapped inside a stacking context, or the modal and overlay are placed in the wrong HTML structure.
Modal z-index Fix
Why is my modal behind the overlay?
A modal behind overlay bug is one of the most confusing CSS problems because the modal exists, the overlay exists, and the code looks almost right. But visually, the dark overlay sits above the modal, the popup looks faded, or the modal cannot be clicked. The real issue is usually layer order: z-index, stacking context, position, transform, or where the modal is placed in the HTML.
- Modal z-index
- Overlay layer
- Stacking context
- Click blocking
What the bug looks like
The modal appears dim, sits under the dark background, cannot be clicked, or looks like it opens behind the page.
Why it happens
The overlay and modal are not in the right stacking order, or the modal is trapped inside a lower stacking context.
What usually fixes it
Put the overlay and modal in one predictable layer system, then make the modal layer higher than the overlay.
The overlay has a higher z-index than the modal
This is the simplest version of the bug. The overlay is placed above the page, but the modal is not placed above the overlay. The result is a popup that looks hidden, darkened, or unclickable.
Broken code
Overlay wins.overlay {
position: fixed;
inset: 0;
z-index: 1000;
}
.modal {
position: fixed;
z-index: 50;
}
Broken visual result
The popup is lower than the overlay layer.
Correct code
Modal wins.overlay {
position: fixed;
inset: 0;
z-index: 1000;
}
.modal {
position: fixed;
z-index: 1001;
}
Fixed visual result
The popup is now above the overlay layer.
The modal is trapped inside a stacking context
A modal can have a huge z-index and still lose if it is inside a parent stacking context. A transformed parent, filtered parent, or positioned parent with its own z-index can trap the modal below the page overlay.
Broken code
Trapped modal.card {
transform: translateZ(0);
z-index: 1;
}
.card .modal {
position: fixed;
z-index: 9999;
}
Broken visual result
The modal is inside a lower parent context.
Correct code
Page-level modal<body>
<main class="page">...</main>
<div class="overlay"></div>
<div class="modal">...</div>
</body>
Fixed visual result
The modal is a sibling of the overlay at page level.
The modal has z-index, but no useful positioning
Developers often add z-index to a modal and expect it to jump above everything. But if the element is not positioned or not participating in a stacking order that accepts z-index, the value may not solve the layer problem.
Broken code
z-index without position.overlay {
position: fixed;
inset: 0;
z-index: 20;
}
.modal {
z-index: 100;
}
Broken visual result
The modal layer is not defined clearly.
Correct code
Positioned modal layer.overlay {
position: fixed;
inset: 0;
z-index: 20;
}
.modal {
position: fixed;
inset: auto;
z-index: 30;
}
Fixed visual result
The modal is positioned and layered above the overlay.
The HTML order makes the overlay cover the modal
When two positioned elements are in the same stacking level, later elements can paint above earlier elements. If the overlay is inserted after the modal and both use similar z-index values, the overlay may cover the modal.
Broken code
Overlay after modal<div class="modal">...</div>
<div class="overlay"></div>
Broken visual result
The overlay is inserted after this layer.
Correct code
Explicit layer order<div class="overlay"></div>
<div class="modal">...</div>
Fixed visual result
The modal is inserted and layered above the overlay.
A production-minded modal layer pattern
A reliable modal system uses named layer values, keeps modal and overlay close together in the DOM, and avoids placing modals inside transformed cards, sliders, headers, or small layout wrappers.
Premium code
Predictable modal stack<div class="modal-root">
<div class="modal-overlay"></div>
<section class="modal-dialog" role="dialog" aria-modal="true">
...
</section>
</div>
:root {
--layer-overlay: 1000;
--layer-modal: 1010;
}
.modal-overlay {
position: fixed;
inset: 0;
z-index: var(--layer-overlay);
background: rgba(15, 23, 42, .64);
}
.modal-dialog {
position: fixed;
left: 50%;
top: 50%;
z-index: var(--layer-modal);
transform: translate(-50%, -50%);
width: min(100% - 32px, 480px);
}
Premium visual result
The overlay and dialog have predictable, named layers.
Fast practical rule
If your modal is behind the overlay, compare the overlay layer and the modal layer first. Then inspect the modal’s parents for stacking context traps like transform, opacity, filter, isolation, and positioned wrappers.
Debug checklist
- Inspect the overlay and modal in DevTools and compare their computed
z-indexvalues. - Make sure both overlay and modal have a real position, usually
position:fixed. - Keep the modal z-index higher than the overlay z-index.
- Check whether the modal is inside a transformed, filtered, or positioned parent.
- Move app-level modals near the end of the document or into a dedicated modal root.
- Avoid random values like
z-index:999999; use a small layer scale instead. - Check whether the overlay is stealing clicks with
pointer-events. - Verify that the modal is not inside a header, slider, card, or overflow-hidden wrapper.
transform traps the modal inside a lower stacking context.
Related fixes that can help
Modal behind overlay bugs are usually connected to z-index, stacking context, HTML structure, and invisible click-blocking layers.
Final takeaway
A modal behind overlay problem is usually not fixed by throwing a bigger z-index at the modal. The real fix is to understand which stacking context the modal belongs to and whether the overlay is above it.
Place the overlay and modal in a predictable page-level layer, give the overlay a lower layer than the modal, and avoid trapping the modal inside transformed or overflow-heavy parents.