Z-Index Token Scale
Z-Index Token Scale
A z-index token scale establishes an organized system for element stacking order, preventing the “z-index wars” that occur when developers escalate values to ensure their element appears on top. Without a managed scale, z-index values proliferate randomly, creating unpredictable stacking behavior and maintenance headaches. A tokenized scale brings order to layering.
What Is a Z-Index Token Scale
A z-index token scale is a predefined set of z-index values assigned to specific use cases. Rather than developers choosing arbitrary numbers, they select from a vocabulary of named stacking levels with clear semantic meaning.
The scale defines relationships: tooltips appear above popovers, popovers above modals, modals above the base content. These relationships remain consistent regardless of where elements appear in the DOM.
How Z-Index Token Scales Work
A typical z-index scale defines levels for common UI patterns:
{
"zIndex": {
"base": { "value": "0" },
"raised": { "value": "1" },
"dropdown": { "value": "1000" },
"sticky": { "value": "1100" },
"fixed": { "value": "1200" },
"drawerBackdrop": { "value": "1300" },
"drawer": { "value": "1400" },
"modalBackdrop": { "value": "1500" },
"modal": { "value": "1600" },
"popover": { "value": "1700" },
"tooltip": { "value": "1800" },
"notification": { "value": "1900" }
}
}
CSS application:
.tooltip {
z-index: var(--z-index-tooltip);
}
.modal {
z-index: var(--z-index-modal);
}
.modal-backdrop {
z-index: var(--z-index-modal-backdrop);
}
The gaps between values (100 in this example) provide room for insertion without restructuring the entire scale. If something needs to appear between modal and popover, values in the 1600-1700 range are available.
Key Considerations
- Gaps between values accommodate future additions
- Paired values (backdrop + content) maintain relationships
- Stacking contexts affect how z-index values interact
- Negative z-index can be useful but adds complexity
- Scale should cover all common UI patterns
- Documentation should explain when to use each level
- Arbitrary values outside the scale should be discouraged
- Scale values should be large enough to exceed incidental z-index
Common Questions
How do stacking contexts affect z-index tokens?
CSS stacking contexts isolate z-index values within their scope. This is both a feature and a source of confusion.
A new stacking context is created by elements with:
- Position: fixed or sticky
- Position: absolute/relative with z-index other than auto
- Opacity less than 1
- Transform, filter, perspective properties
- Isolation: isolate
- And several other CSS properties
Within a stacking context, z-index values only compete with siblings in the same context:
<div style="position: relative; z-index: 1;">
<!-- Stacking context A -->
<div style="position: relative; z-index: 9999;">
<!-- This 9999 only matters within context A -->
</div>
</div>
<div style="position: relative; z-index: 2;">
<!-- Stacking context B - appears above context A -->
<div style="position: relative; z-index: 1;">
<!-- This 1 appears above the 9999 in context A -->
</div>
</div>
Z-index tokens cannot override stacking context boundaries. Teams must understand that tokens establish ordering within contexts, not absolute ordering across all contexts.
Best practices:
- Avoid unnecessary stacking context creation
- Document which components create stacking contexts
- Consider portaling overlays to consistent DOM locations
How should negative z-index be handled?
Negative z-index places elements behind their stacking context root. This can be useful but adds complexity.
Common use cases:
- Background decorations that appear behind content
- Pseudo-element backgrounds
- Layered visual effects
If negative values are needed:
{
"zIndex": {
"below": { "value": "-1" },
"base": { "value": "0" },
"raised": { "value": "1" }
}
}
Caution: elements with negative z-index can become unclickable if they fall behind their parent’s background. This creates accessibility issues for interactive elements.
Many design systems avoid negative z-index in the token scale, treating it as an implementation detail rather than a semantic level.
How should the scale handle edge cases?
Edge cases arise when standard levels do not fit a specific need.
Nested overlays: A popover inside a modal should appear above the modal. If both use fixed values, the popover appears below (modal is higher in the scale). Solutions include:
- Using stacking context isolation so the popover’s z-index operates within the modal context
- Defining relative levels like
modal-content: 1,modal-popover: 2within the modal context
Third-party components: Libraries may use hardcoded z-index values that conflict with token scale. Solutions include:
- CSS overrides targeting library classes
- Wrapper components that establish containing stacking contexts
- Configuration options if libraries support them
Emergency overrides: When absolutely necessary, clearly document exceptions:
/* Exception: Legacy banner requires specific positioning */
/* TODO: Refactor when banner component is updated */
.legacy-banner {
z-index: 1850; /* Between tooltip and notification */
}
Exceptions should be rare and tracked for eventual resolution.
Summary
Z-index token scales bring order to element stacking by defining a vocabulary of named levels with clear relationships. Gaps between values accommodate future additions. Understanding CSS stacking contexts is essential since tokens establish ordering within contexts, not across them. Negative z-index adds complexity and is often best avoided in scales. Edge cases require careful handling through stacking context management or documented exceptions.
Buoy scans your codebase for design system inconsistencies before they ship
Detect Design Drift Free