From 3ad4c5d5b04aab4cb84da6a2d6d77ae7a8932a8e Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Mon, 6 Apr 2026 13:24:37 -0700 Subject: [PATCH 1/3] Refactor how we do zindex - Move to a combined Sass map - Generate tokens on the root for all values - Update components to use CSS variables instead --- scss/_config.scss | 22 ++++++++------------ scss/_datepicker.scss | 2 +- scss/_dialog.scss | 2 +- scss/_drawer.scss | 2 +- scss/_menu.scss | 2 +- scss/_popover.scss | 2 +- scss/_root.scss | 5 +++++ scss/_toasts.scss | 4 ++-- scss/_tooltip.scss | 2 +- scss/helpers/_position.scss | 8 +++---- site/src/content/docs/layout/z-index.mdx | 2 +- site/src/content/docs/utilities/z-index.mdx | 23 +++++++++++++++++++-- 12 files changed, 48 insertions(+), 28 deletions(-) diff --git a/scss/_config.scss b/scss/_config.scss index c30393fb8b1e..5d8bdea5d33c 100644 --- a/scss/_config.scss +++ b/scss/_config.scss @@ -301,24 +301,20 @@ $font-sizes: defaults( // Warning: Avoid customizing these values. They're used for a bird's eye view // of components dependent on the z-axis and are designed to all work together. -// scss-docs-start zindex-stack -$zindex-menu: 1000 !default; -$zindex-sticky: 1020 !default; -$zindex-fixed: 1030 !default; -// $zindex-drawer-backdrop: 1040 !default; -$zindex-drawer: 1045 !default; -$zindex-dialog: 1055 !default; -$zindex-popover: 1070 !default; -$zindex-tooltip: 1080 !default; -$zindex-toast: 1090 !default; -// scss-docs-end zindex-stack - // scss-docs-start zindex-levels-map $zindex-levels: ( n1: -1, 0: 0, 1: 1, 2: 2, - 3: 3 + 3: 3, + menu: 1000, + sticky: 1010, + fixed: 1020, + drawer: 1030, + dialog: 1040, + popover: 1050, + tooltip: 1060, + toast: 1070, ) !default; // scss-docs-end zindex-levels-map diff --git a/scss/_datepicker.scss b/scss/_datepicker.scss index d45f1e39a5e9..f43e6b33b6c2 100644 --- a/scss/_datepicker.scss +++ b/scss/_datepicker.scss @@ -22,7 +22,7 @@ $datepicker-tokens: defaults( --datepicker-box-shadow: var(--box-shadow), --datepicker-font-size: var(--font-size-sm), --datepicker-min-width: 280px, - --datepicker-zindex: #{$zindex-menu}, + --datepicker-zindex: var(--z-menu), --datepicker-header-font-weight: 600, --datepicker-weekday-color: var(--fg-3), --datepicker-day-hover-bg: var(--bg-1), diff --git a/scss/_dialog.scss b/scss/_dialog.scss index 0e9cf1975d67..00399ccf31d6 100644 --- a/scss/_dialog.scss +++ b/scss/_dialog.scss @@ -185,7 +185,7 @@ $dialog-sizes: defaults( position: fixed; inset-block-start: 50%; inset-inline-start: 50%; - z-index: $zindex-dialog; + z-index: var(--z-dialog); margin-inline: 0; transform: translate(-50%, -50%); } diff --git a/scss/_drawer.scss b/scss/_drawer.scss index ac45e076d6fb..bafb97b363ff 100644 --- a/scss/_drawer.scss +++ b/scss/_drawer.scss @@ -16,7 +16,7 @@ $drawer-tokens: () !default; $drawer-tokens: defaults( ( --drawer-inset: var(--spacer), - --drawer-zindex: #{$zindex-drawer}, + --drawer-zindex: var(--z-drawer), --drawer-width: 400px, --drawer-height: 30vh, --drawer-padding-x: var(--spacer), diff --git a/scss/_menu.scss b/scss/_menu.scss index 7dba484b6bf2..eb6cf0477460 100644 --- a/scss/_menu.scss +++ b/scss/_menu.scss @@ -11,7 +11,7 @@ $menu-tokens: () !default; // scss-docs-start menu-tokens $menu-tokens: defaults( ( - --menu-zindex: #{$zindex-menu}, + --menu-zindex: var(--z-menu), --menu-gap: .125rem, --menu-min-width: 10rem, --menu-padding-x: .25rem, diff --git a/scss/_popover.scss b/scss/_popover.scss index cb18beeae9b9..2a97fd157de7 100644 --- a/scss/_popover.scss +++ b/scss/_popover.scss @@ -11,7 +11,7 @@ $popover-tokens: () !default; // stylelint-disable-next-line scss/dollar-variable-default $popover-tokens: defaults( ( - --popover-zindex: #{$zindex-popover}, + --popover-zindex: var(--z-popover), --popover-max-width: 280px, --popover-font-size: var(--font-size-sm), --popover-bg: var(--bg-body), diff --git a/scss/_root.scss b/scss/_root.scss index ded286a7a906..6fbf36a23893 100644 --- a/scss/_root.scss +++ b/scss/_root.scss @@ -178,6 +178,11 @@ $root-tokens: map.set($root-tokens, --radius-pill, 50rem); } // scss-docs-end root-box-shadow-loop +// Generate z-index tokens +@each $key, $value in $zindex-levels { + $root-tokens: map.set($root-tokens, --z-#{$key}, $value); +} + :root { @include tokens($root-tokens); diff --git a/scss/_toasts.scss b/scss/_toasts.scss index 6b6359ea5267..435b1270880c 100644 --- a/scss/_toasts.scss +++ b/scss/_toasts.scss @@ -10,7 +10,7 @@ $toast-tokens: () !default; // stylelint-disable-next-line scss/dollar-variable-default $toast-tokens: defaults( ( - --toast-zindex: #{$zindex-toast}, + --toast-zindex: var(--z-toast), --toast-padding-x: 1rem, --toast-padding-y: .75rem, --toast-spacing: #{$container-padding-x}, @@ -59,7 +59,7 @@ $toast-tokens: defaults( } .toast-container { - --toast-zindex: #{$zindex-toast}; + --toast-zindex: var(--z-toast); position: absolute; z-index: var(--toast-zindex); diff --git a/scss/_tooltip.scss b/scss/_tooltip.scss index ccbb6bb0bdbd..a74e99f46ec3 100644 --- a/scss/_tooltip.scss +++ b/scss/_tooltip.scss @@ -10,7 +10,7 @@ $tooltip-tokens: () !default; // stylelint-disable-next-line scss/dollar-variable-default $tooltip-tokens: defaults( ( - --tooltip-zindex: #{$zindex-tooltip}, + --tooltip-zindex: var(--z-tooltip), --tooltip-max-width: 200px, --tooltip-padding-x: var(--spacer-3), --tooltip-padding-y: calc(var(--spacer) * .375), diff --git a/scss/helpers/_position.scss b/scss/helpers/_position.scss index 3c94967d251d..34c76f9a5be6 100644 --- a/scss/helpers/_position.scss +++ b/scss/helpers/_position.scss @@ -6,13 +6,13 @@ .fixed-top { position: fixed; inset: 0 0 auto; - z-index: $zindex-fixed; + z-index: var(--z-fixed); } .fixed-bottom { position: fixed; inset: auto 0 0; - z-index: $zindex-fixed; + z-index: var(--z-fixed); } // Responsive sticky top and bottom @@ -23,13 +23,13 @@ .#{$prefix}sticky-top { position: sticky; top: 0; - z-index: $zindex-sticky; + z-index: var(--z-sticky); } .#{$prefix}sticky-bottom { position: sticky; bottom: 0; - z-index: $zindex-sticky; + z-index: var(--z-sticky); } } } diff --git a/site/src/content/docs/layout/z-index.mdx b/site/src/content/docs/layout/z-index.mdx index 7cfd2b78a7b1..1549bd96fbf4 100644 --- a/site/src/content/docs/layout/z-index.mdx +++ b/site/src/content/docs/layout/z-index.mdx @@ -9,6 +9,6 @@ These higher values start at an arbitrary number, high and specific enough to id We don’t encourage customization of these individual values; should you change one, you likely need to change them all. - + To handle overlapping borders within components (e.g., buttons and inputs in input groups), we use low single digit `z-index` values of `1`, `2`, and `3` for default, hover, and active states. On hover/focus/active, we bring a particular element to the forefront with a higher `z-index` value to show their border over the sibling elements. diff --git a/site/src/content/docs/utilities/z-index.mdx b/site/src/content/docs/utilities/z-index.mdx index 484130790fb2..a65c9d36dafe 100644 --- a/site/src/content/docs/utilities/z-index.mdx +++ b/site/src/content/docs/utilities/z-index.mdx @@ -10,9 +10,9 @@ utility: Use `z-index` utilities to stack elements on top of one another. Requires a `position` value other than `static`, which can be set with custom styles or using our [position utilities]([[docsref:/utilities/position/]]). - +### Low-level stack + We call these “low-level” `z-index` utilities because of their default values of `-1` through `3`, which we use for the layout of overlapping components. High-level `z-index` values are used for overlay components like modals and tooltips. - z-3
z-2
@@ -20,6 +20,25 @@ We call these “low-level” `z-index` utilities because of their default value
z-0
z-n1
`} /> +### Component stack + +The component `z-index` utilities are used for overlay components like dialogs, popovers, and more. Classes are available for all of them, and their CSS variables are used in their respective components out of the box. + + +| Class | Value | CSS variable | +| --- | --- | --- | +| `z-menu` | `1000` | `var(--z-menu)` | +| `z-sticky` | `1010` | `var(--z-sticky)` | +| `z-fixed` | `1020` | `var(--z-fixed)` | +| `z-drawer` | `1030` | `var(--z-drawer)` | +| `z-dialog` | `1040` | `var(--z-dialog)` | +| `z-popover` | `1050` | `var(--z-popover)` | +| `z-tooltip` | `1060` | `var(--z-tooltip)` | +| `z-toast` | `1070` | `var(--z-toast)` | + + +Read more about the component `z-index` values in the [`z-index` layout page]([[docsref:/layout/z-index]]). + ## Overlays Bootstrap overlay components—menu, dialog, drawer, popover, toast, and tooltip—all have their own `z-index` values to ensure a usable experience with competing “layers” of an interface. From f3b8a6368acf846f01c6adaf8974134a0845fa47 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Mon, 6 Apr 2026 13:25:48 -0700 Subject: [PATCH 2/3] generate utils info --- dist/css/bootstrap-utilities.metadata.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dist/css/bootstrap-utilities.metadata.json b/dist/css/bootstrap-utilities.metadata.json index 39afc25241d0..33319d7dfb54 100644 --- a/dist/css/bootstrap-utilities.metadata.json +++ b/dist/css/bootstrap-utilities.metadata.json @@ -1409,7 +1409,15 @@ "z-0", "z-1", "z-2", - "z-3" + "z-3", + "z-menu", + "z-sticky", + "z-fixed", + "z-drawer", + "z-dialog", + "z-popover", + "z-tooltip", + "z-toast" ] } } From 39851f510e6bfe68cd656e445db15c6e9ff5b6b3 Mon Sep 17 00:00:00 2001 From: Mark Otto Date: Thu, 16 Jul 2026 21:40:16 -0700 Subject: [PATCH 3/3] fix --- .bundlewatch.config.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index 00ac4e5b5f14..7c5c1399761e 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -18,19 +18,19 @@ }, { "path": "./dist/css/bootstrap-utilities.css", - "maxSize": "18.5 kB" + "maxSize": "18.75 kB" }, { "path": "./dist/css/bootstrap-utilities.min.css", - "maxSize": "17.25 kB" + "maxSize": "17.5 kB" }, { "path": "./dist/css/bootstrap.css", - "maxSize": "50.25 kB" + "maxSize": "50.5 kB" }, { "path": "./dist/css/bootstrap.min.css", - "maxSize": "46.5 kB" + "maxSize": "46.75 kB" }, { "path": "./dist/js/bootstrap.bundle.js",