Skip to content

Add z-index design tokens for stacking context management#1319

Merged
lukasoppermann merged 5 commits intomainfrom
z-index-tokens
Feb 23, 2026
Merged

Add z-index design tokens for stacking context management#1319
lukasoppermann merged 5 commits intomainfrom
z-index-tokens

Conversation

@lukasoppermann
Copy link
Copy Markdown
Collaborator

Summary

Introduces z-index design tokens to manage stacking context, preventing ad-hoc magic numbers and z-index conflicts.

New tokens

Token Value Use cases
zIndex.behind -1 Decorative backgrounds, canvas elements
zIndex.default 0 Normal stacking, reset
zIndex.sticky 100 Sticky headers, sidebars, table headers
zIndex.dropdown 200 Menus, select panels, autocomplete
zIndex.overlay 300 Backdrops, drawers, side panels
zIndex.modal 400 Modal dialogs
zIndex.popover 500 Tooltips, popovers, hover cards
zIndex.skipLink 600 Accessibility skip links (always topmost)

Shadow ↔ Z-Index alignment

Shadow Level Z-Index Token
shadow.resting.* zIndex.default / zIndex.sticky
shadow.floating.small/medium zIndex.dropdown / zIndex.overlay
shadow.floating.large/xlarge zIndex.modal / zIndex.popover

Changes

  • src/tokens/base/size/z-index.json5 — base numeric scale (0, 1, 100–600)
  • src/tokens/functional/size/z-index.json5 — 8 semantic tokens with LLM metadata
  • DESIGN_TOKENS_GUIDE.md — z-index rules and shadow alignment table
  • DESIGN_TOKENS_SPEC.md — auto-generated with all z-index entries

Introduce base z-index scale (0-600) and 8 semantic functional tokens:
- behind (-1): decorative backgrounds
- default (0): normal stacking
- sticky (100): sticky headers/sidebars
- dropdown (200): menus, select panels
- overlay (300): backdrops, drawers
- modal (400): dialogs
- popover (500): tooltips, popovers
- skipLink (600): accessibility skip navigation

Includes LLM metadata with usage guidance, shadow-to-z-index alignment
rules in DESIGN_TOKENS_GUIDE.md, and auto-generated DESIGN_TOKENS_SPEC.md
entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 20, 2026 14:47
@lukasoppermann lukasoppermann requested review from a team as code owners February 20, 2026 14:47
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 20, 2026

🦋 Changeset detected

Latest commit: cc6134f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/primitives Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 20, 2026

Design Token Diff (CSS)

/css/primitives.css

+++ /home/runner/work/primitives/primitives/dist/css/primitives.css	2026-02-23 09:25:14.485651933 +0000
@@ -4,6 +4,7 @@
*/
@import './base/motion/motion.css';
@import './base/size/size.css';
+@import './base/size/z-index.css';
@import './base/typography/typography.css';
@import './functional/size/border.css';
@import './functional/size/breakpoints.css';
@@ -11,4 +12,5 @@
@import './functional/size/size-coarse.css';
@import './functional/size/size-fine.css';
@import './functional/size/size.css';
+@import './functional/size/z-index.css';
@import './functional/typography/typography.css';

This comment was marked as outdated.

lukasoppermann and others added 2 commits February 20, 2026 16:33
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use glob 'src/tokens/base/size/*.json5' for includes so functional
  z-index references to base.zIndex.* resolve correctly
- Add base z-index build output (base/size/z-index.css)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 23, 2026

@lukasoppermann I've opened a new pull request, #1321, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tokens/base/size/z-index.json5
Copilot AI and others added 2 commits February 23, 2026 10:23
…lm` convention (#1321)

* Initial plan

* Fix rules field formatting in z-index.json5 to match org.primer.llm convention

Co-authored-by: lukasoppermann <813754+lukasoppermann@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: lukasoppermann <813754+lukasoppermann@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +6 to +30
$type: 'number',
},
'100': {
$value: 100,
$type: 'number',
},
'200': {
$value: 200,
$type: 'number',
},
'300': {
$value: 300,
$type: 'number',
},
'400': {
$value: 400,
$type: 'number',
},
'500': {
$value: 500,
$type: 'number',
},
'600': {
$value: 600,
$type: 'number',
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All base size tokens in the codebase include org.primer.figma extensions with collection and scopes metadata. The z-index base tokens should follow the same pattern for consistency with other base/size tokens. Consider adding Figma extensions to each token entry similar to how they appear in base/size/size.json5.

Suggested change
$type: 'number',
},
'100': {
$value: 100,
$type: 'number',
},
'200': {
$value: 200,
$type: 'number',
},
'300': {
$value: 300,
$type: 'number',
},
'400': {
$value: 400,
$type: 'number',
},
'500': {
$value: 500,
$type: 'number',
},
'600': {
$value: 600,
$type: 'number',
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},
},
'100': {
$value: 100,
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},
},
'200': {
$value: 200,
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},
},
'300': {
$value: 300,
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},
},
'400': {
$value: 400,
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},
},
'500': {
$value: 500,
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},
},
'600': {
$value: 600,
$type: 'number',
$extensions: {
'org.primer.figma': {
collection: 'z-index',
scopes: ['base'],
},
},

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +90
behind: {
$value: -1,
$type: 'number',
$description: 'Place element behind base content. Use for decorative backgrounds or canvas elements.',
$extensions: {
'org.primer.llm': {
usage: ['decorative-background', 'canvas-element', 'background-pattern'],
rules: 'Use to push an element behind its siblings. WARNING: Negative z-index can behave unpredictably if any ancestor creates a new stacking context (via transform, opacity < 1, filter, will-change, etc.). Only use when you control the full stacking context chain. Do NOT use as a general "hide" mechanism.',
},
},
},
default: {
$value: '{base.zIndex.0}',
$type: 'number',
$description: 'Default stacking order. No elevation above surrounding content.',
$extensions: {
'org.primer.llm': {
usage: ['default-content', 'in-flow-element', 'reset'],
rules: 'Use to explicitly reset z-index to the default layer. Suitable for elements that should participate in normal document flow stacking. Do NOT use for any element that needs to appear above other content.',
},
},
},
sticky: {
$value: '{base.zIndex.100}',
$type: 'number',
$description: 'Sticky elements that remain visible while scrolling.',
$extensions: {
'org.primer.llm': {
usage: ['sticky-header', 'sticky-sidebar', 'sticky-table-header', 'sticky-footer', 'sticky-nav'],
rules: 'MUST use with `position: sticky` or `position: fixed` for headers, sidebars, and navigation bars that persist during scroll. Do NOT use for floating overlays or dropdowns — use higher z-index levels instead.',
},
},
},
dropdown: {
$value: '{base.zIndex.200}',
$type: 'number',
$description: 'Dropdown menus and select panels that appear above page content.',
$extensions: {
'org.primer.llm': {
usage: ['dropdown-menu', 'select-panel', 'autocomplete-list', 'action-menu', 'context-menu'],
rules: 'Use for menus, select panels, and autocomplete lists that overlay page content. These should appear above sticky elements but below overlays and modals. Pair with `shadow.floating.small` or `shadow.floating.medium` for visual elevation.',
},
},
},
overlay: {
$value: '{base.zIndex.300}',
$type: 'number',
$description: 'Overlay backdrops, side panels, and drawers.',
$extensions: {
'org.primer.llm': {
usage: ['overlay-backdrop', 'side-panel', 'drawer', 'slide-over', 'bottom-sheet'],
rules: 'Use for overlay surfaces that partially cover the page — drawers, side panels, and backdrop layers. These appear above dropdowns but below modal dialogs. SHOULD be paired with a backdrop/scrim element to indicate the overlay is blocking interaction with content beneath.',
},
},
},
modal: {
$value: '{base.zIndex.400}',
$type: 'number',
$description: 'Modal dialogs and full-screen overlays.',
$extensions: {
'org.primer.llm': {
usage: ['modal-dialog', 'dialog', 'full-screen-overlay', 'lightbox', 'confirm-dialog'],
rules: 'Use for modal dialogs that require user interaction before returning to the page. MUST trap focus within the modal. MUST appear above all other page content except popovers and skip links. Pair with `shadow.floating.large` or `shadow.floating.xlarge` for visual elevation.',
},
},
},
popover: {
$value: '{base.zIndex.500}',
$type: 'number',
$description: 'Tooltips and popovers that appear above all normal UI.',
$extensions: {
'org.primer.llm': {
usage: ['tooltip', 'popover', 'hover-card', 'floating-label'],
rules: 'Use for tooltips, popovers, and hover cards that must appear above all other UI elements including modals. These are the highest layer in normal UI. Do NOT use for persistent navigation — use `sticky` instead.',
},
},
},
skipLink: {
$value: '{base.zIndex.600}',
$type: 'number',
$description: 'Accessibility skip links. Must always be the topmost layer.',
$extensions: {
'org.primer.llm': {
usage: ['skip-link', 'skip-navigation', 'skip-to-content'],
rules: 'MUST use for accessibility skip links that allow keyboard users to bypass navigation. This is the highest z-index level and MUST always appear above everything else including modals and tooltips. NEVER use for non-accessibility purposes.',
},
},
},
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All functional size tokens in the codebase include org.primer.figma extensions with collection and scopes metadata. The z-index functional tokens should follow the same pattern for consistency. For reference, see how radius.json5 and border.json5 include both org.primer.figma and org.primer.llm extensions. Consider adding Figma extensions to each token entry.

Copilot uses AI. Check for mistakes.
@lukasoppermann lukasoppermann merged commit dccf2af into main Feb 23, 2026
31 checks passed
@lukasoppermann lukasoppermann deleted the z-index-tokens branch February 23, 2026 10:02
@primer primer bot mentioned this pull request Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants