z-index
Tailwind z-index scale: stacking order made predictable. The named layers, custom values, and the patterns that prevent z-index wars.
Tailwind — z-index
EXAMPLE
<!-- ===== Default scale ===== -->
<!-- z-0 z-10 z-20 z-30 z-40 z-50 -->
<!-- z-auto -->
<div class="z-0">base</div>
<div class="z-10">above</div>
<!-- Negative: -z-10 -z-20 ... -->
<div class="-z-10">behind</div>
<!-- ===== Arbitrary values ===== -->
<div class="z-[100]">specific</div>
<div class="z-[999]">very specific</div>
<!-- ===== Common UI layer plan ===== -->
<!--
z-0 base content
z-10 sticky elements (sidebar, header in flow)
z-20 dropdowns
z-30 sticky overlays (banner)
z-40 modal backdrops + dialogs
z-50 toasts + notifications
Above 50: reserve for absolute top-of-stack (auth wall, debug overlay).
-->
<!-- ===== Custom scale in tailwind.config.js ===== -->
<!--
extend: {
zIndex: {
base: '0',
dropdown: '20',
sticky: '30',
modal: '40',
toast: '50',
overlay: '999',
},
},
-->
<!-- Then use: -->
<div class="z-modal">...</div>
<!-- ===== Stacking contexts ===== -->
<!--
A z-index only matters inside its STACKING CONTEXT.
A new context is created by:
- position: relative/absolute/fixed/sticky + z-index != auto
- opacity < 1
- transform != none
- filter, perspective, etc.
If your modal is inside a parent with opacity < 1, it WILL NOT escape that context.
Move overlays to a top-level portal to avoid this.
-->
<!-- ===== Common bug + fix ===== -->
<!-- The bug: nested z-index wars -->
<div class="opacity-90"> <!-- creates a stacking context -->
<div class="fixed inset-0 z-50 bg-black/50"> <!-- still bounded by parent -->
<div class="bg-white">Modal</div>
</div>
</div>
<!-- The fix: render the modal in a portal at <body> root -->
<!-- React: ReactDOM.createPortal(<Modal/>, document.body) -->
<!-- Vue: <Teleport to="body"><Modal/></Teleport> -->
<!-- Svelte: use:portal or a wrapper component -->
<!-- ===== Sticky + z ===== -->
<div class="sticky top-0 z-30 bg-white border-b">Header</div>
<!-- Sticky elements need a non-auto z-index to lay above content beneath. -->
<!-- ===== Pitfalls ===== -->
<!-- - Inflating z values to win wars (z-9999) hides root cause (stacking context) -->
<!-- - Forgetting that opacity / transform creates a new stacking context -->
<!-- - Mixing static + arbitrary values without a scale -->
<!-- - Tooltips inside a transformed parent -> appear behind unrelated elements -->
<!-- ===== Patterns to internalise =====
- Use 0/10/20/30/40/50 as named UI layers
- Portal modals + toasts to body root
- Avoid arbitrary z values; if you need 100+, you have a stacking context problem
- Document the layer plan once; teach the team
-->
Why it matters
Tailwind z-index works best when paired with a named layer plan (dropdown / modal / toast / overlay). The real bugs are stacking context — overlays inside opacity/transform parents do not escape. Portal them to body and the scale becomes predictable.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…