Managing z-index across multiple stacked dialogs in React gets messy fast. I ran this problem through an AI tool out of curiosity and it generated this:
jsxconst DialogManager = ({ dialogs }) => {
return (
<>
{dialogs.map((dialog, index) => {
const zIndexBackdrop = 1000 + (5 * (index + 1));
const zIndexContent = zIndexBackdrop + 2;
return (
<div key={dialog.id}>
<div
className="modal-backdrop show"
style={{ zIndex: zIndexBackdrop }}
/>
<div
role="dialog"
aria-modal="true"
style={{ zIndex: zIndexContent }}
>
{dialog.content}
</div>
</div>
);
})}
</>
);
};
Functional, but it runs the z-index calculation on every render cycle. For a static stacking requirement, that's unnecessary execution. Styling problems should be solved in the style layer.
Here's the approach I came up with using SCSS:
@for $i from 1 through 6 {
$zIndexBackdrop: #{1000 + (5 * $i)};
$zIndexContent: #{1000 + (5 * $i) + 2};
.modal-backdrop.show:nth-of-type(#{$i}) {
z-index: $zIndexBackdrop;
}
div[role="dialog"][aria-modal="true"]:nth-of-type(#{$i}) {
z-index: $zIndexContent;
}
}
This loop generates z-index rules for up to 6 dialog layers at compile time - zero runtime cost. The backdrop and content for each layer are spaced 2 units apart, with 5-unit gaps between layers to leave room for other elements if needed.
A few things to know before using this:
-
nth-of-typeis sensitive to DOM structure. If other elements of the same type exist in the same context, the selector can misfire. Verify your rendered DOM matches the assumption. - The ceiling of
6is arbitrary — adjust the loop range, base value, and step size to fit yourz-indexscale. - This compiles down to plain CSS. No runtime, no state, no effect hooks. That's the point.
Top comments (0)