Add z-index design tokens for stacking context management#1319
Add z-index design tokens for stacking context management#1319lukasoppermann merged 5 commits intomainfrom
Conversation
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>
🦋 Changeset detectedLatest commit: cc6134f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
Design Token Diff (CSS)
|
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>
|
@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. |
There was a problem hiding this comment.
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.
…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>
There was a problem hiding this comment.
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.
| $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', |
There was a problem hiding this comment.
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.
| $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'], | |
| }, | |
| }, |
| 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.', | ||
| }, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
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.
Summary
Introduces z-index design tokens to manage stacking context, preventing ad-hoc magic numbers and z-index conflicts.
New tokens
zIndex.behindzIndex.defaultzIndex.stickyzIndex.dropdownzIndex.overlayzIndex.modalzIndex.popoverzIndex.skipLinkShadow ↔ Z-Index alignment
shadow.resting.*zIndex.default/zIndex.stickyshadow.floating.small/mediumzIndex.dropdown/zIndex.overlayshadow.floating.large/xlargezIndex.modal/zIndex.popoverChanges
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 metadataDESIGN_TOKENS_GUIDE.md— z-index rules and shadow alignment tableDESIGN_TOKENS_SPEC.md— auto-generated with all z-index entries