z-index: 999, your colleague sets 1000, and before long you're writing z-index: 99999 just to show a tooltip. 😅
This is the z-index war — and there are no winners.
Using huge numbers is a code smell. But the worst part is that it often doesn't even work. Why? Because of the Stacking Context.
What is Stacking Context?
opacity, transform, or position create new "mini-worlds" where z-index counting starts over. Your z-index: 9999 in one world can easily end up beneath z-index: 1 in another.
/* Parent creates a new stacking context */
.parent {
transform: translateZ(0); /* triggers new context */
position: relative;
}
/* This z-index is now scoped to .parent's world */
.child {
z-index: 9999; /* won't escape .parent */
}opacity (less than 1), transform, filter, will-change, isolation: isolate.
The solution — organization, not higher numbers
:root or Tailwind config:
/* In your :root */
:root {
--z-dropdown: 10;
--z-header: 20;
--z-tooltip: 30;
--z-modal: 50;
--z-notification: 100;
}// tailwind.config.js
module.exports = {
theme: {
extend: {
zIndex: {
'dropdown': '10',
'header': '20',
'tooltip': '30',
'modal': '50',
'notification': '100',
},
},
},
};/* ❌ Before */
.modal {
z-index: 99999;
}
/* ✅ After */
.modal {
z-index: var(--z-modal);
}Why this works
z-index: 9999, pause and ask: do I have a stacking context issue, or do I just need a scale?
How does your team handle z-index — with a scale or by intuition? 😅