🔢z-index Layer System Guide

Guide z-index layering system design for modals, toasts, tooltips, and other UI

z-index Layer Scale Reference

Layerz-indexExamples
Base0Default content, backgrounds
Sticky100Sticky headers, sticky table heads
Dropdown200Select boxes, autocomplete, date pickers
Fixed Nav300FABs, fixed sidebars
Overlay400Modal backdrop, drawer overlay
Modal500Dialogs, confirmation modals
Popover600Popovers, context menus, color pickers
Tooltip700Hover tooltips, help bubbles
Toast800Notifications, snackbars
Loading900Full-screen spinners, skeleton overlays
Critical1000Critical alerts, GDPR cookie banners

What Is a z-index Layer System?

When UI elements overlap, z-index determines which one appears on top. Higher values render in front, but only within the same stacking context. Without a structured scale, codebases end up littered with arbitrary values like z-index: 9999, causing hard-to-debug layering conflicts.

A 100-unit scale (0, 100, 200…) leaves room for intermediate layers while keeping the hierarchy readable at a glance. Every team member knows that anything above 500 is modal territory, above 800 is notification territory, and so on.

Design Principles

Always separate the overlay backdrop (400) from the modal itself (500) so the dim layer sits below the dialog. Toasts (800) must exceed modals (500) so notifications remain visible even when a modal is open. Place full-screen loaders (900) above everything except the most critical banners (1000).

Stacking Context Gotchas

Properties like transform, opacity < 1, filter, and will-change create new stacking contexts. A child's z-index cannot escape its parent's context. Render modals and overlays as direct children of <body> (e.g., via React Portal) to avoid this trap.

Frequently Asked Questions

Should a toast or modal have a higher z-index?

Toasts should be higher. Notifications need to appear above modals, so toasts (800) should always exceed modals (500).

Does z-index work without a position property?

Not on statically positioned elements. z-index only applies when position is relative, absolute, fixed, or sticky. Flexbox and Grid direct children are an exception.

Is z-index: 9999 a bad practice?

It works but creates maintenance problems. Without a defined scale, developers keep adding higher values, leading to conflicts. A structured scale prevents this.