]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
Rename theme text tokens to fg, update utilities (#42295)
authorMark Otto <markd.otto@gmail.com>
Tue, 7 Apr 2026 21:04:31 +0000 (14:04 -0700)
committerGitHub <noreply@github.com>
Tue, 7 Apr 2026 21:04:31 +0000 (15:04 -0600)
With this refactor, our .fg-* and .bg-* and .border-* utilities can be modified by custom CSS, like in our blue theme example.

This also standardizes some nomenclature by using fg instead of text in the token names for theme values, better matching bg. Classes already use this, as do root fg tokens, so this is just a consistency update.

43 files changed:
scss/_accordion.scss
scss/_alert.scss
scss/_avatar.scss
scss/_card.scss
scss/_chip.scss
scss/_list-group.scss
scss/_menu.scss
scss/_root.scss
scss/_theme.scss
scss/_toasts.scss
scss/_utilities.scss
scss/buttons/_button.scss
scss/content/_prose.scss
scss/content/_reboot.scss
scss/content/_tables.scss
scss/forms/_chip-input.scss
scss/forms/_form-variables.scss
scss/forms/_radio.scss
scss/forms/_switch.scss
scss/tests/mixins/_color-modes.test.scss
scss/tests/modules/_configuration.test.scss
site/src/content/docs/components/card.mdx
site/src/content/docs/customize/color-modes.mdx
site/src/content/docs/customize/theme.mdx
site/src/content/docs/getting-started/approach.mdx
site/src/content/docs/getting-started/install.mdx
site/src/content/docs/guides/migration.mdx
site/src/content/docs/utilities/api.mdx
site/src/content/docs/utilities/background.mdx
site/src/content/docs/utilities/border-color.mdx
site/src/content/docs/utilities/colors.mdx
site/src/content/docs/utilities/theme.mdx
site/src/layouts/ExamplesLayout.astro
site/src/libs/placeholder.ts
site/src/scss/_badge.scss
site/src/scss/_component-examples.scss
site/src/scss/_content.scss
site/src/scss/_masthead.scss
site/src/scss/_navbar.scss
site/src/scss/_placeholder-img.scss
site/src/scss/_search.scss
site/src/scss/_sidebar.scss
site/src/scss/_syntax.scss

index f5c2cba8ef991cd8bd3630d12e2bf6e12d146eea..a1cce3fd7694d428cdffe43713567c1dda99eb01 100644 (file)
@@ -106,7 +106,7 @@ $accordion-tokens: defaults(
       border-color: var(--theme-border, var(--accordion-border-color));
 
       > .accordion-header {
-        color: var(--theme-text, var(--accordion-active-color));
+        color: var(--theme-fg, var(--accordion-active-color));
         background-color: var(--theme-bg-subtle, var(--accordion-active-bg));
         box-shadow: inset 0 calc(-1 * var(--accordion-border-width)) 0 var(--theme-border, var(--accordion-border-color));
 
index 90723a4d7e90fc6c0ff2c932fd1d893e8c9f7de1..20a79e2d95e2b594485bfeabcfbf207b8e5f90db 100644 (file)
@@ -13,7 +13,7 @@ $alert-tokens: defaults(
     --alert-bg: var(--theme-bg-subtle, var(--bg-1)),
     --alert-padding-x: #{$spacer},
     --alert-padding-y: #{$spacer},
-    --alert-color: var(--theme-text, inherit),
+    --alert-color: var(--theme-fg, inherit),
     --alert-border-color: var(--theme-border, var(--border-color)),
     --alert-border: var(--border-width) solid var(--alert-border-color),
     --alert-border-radius: var(--border-radius),
index e1171d09c4e3834b3eba08e1add52eb2875699ad..b097e9ce827cc76c6f3e155bd3b6a74c2e8bb8c2 100644 (file)
@@ -75,7 +75,7 @@ $avatar-sizes: defaults(
   }
 
   .avatar-subtle {
-    color: var(--theme-text, var(--avatar-color));
+    color: var(--theme-fg, var(--avatar-color));
     background-color: var(--theme-bg-subtle, var(--avatar-bg));
   }
 
index 11f5729766620a0e91c7c4cc49678d36691a5e0b..7814d495e3782f87ae588c9217609d45e77806b1 100644 (file)
@@ -140,13 +140,13 @@ $card-tokens: defaults(
     border-color: var(--theme-border, var(--card-border-color));
 
     .card-header {
-      color: var(--theme-text-emphasis, currentcolor);
+      color: var(--theme-fg-emphasis, currentcolor);
       background-color: var(--theme-bg-subtle, var(--card-cap-bg));
       border-color: var(--theme-border, var(--card-border-color));
     }
 
     .card-footer {
-      color: var(--theme-text-emphasis, currentcolor);
+      color: var(--theme-fg-emphasis, currentcolor);
       background-color: var(--theme-bg-subtle, var(--card-cap-bg));
       border-color: var(--theme-border, var(--card-border-color));
     }
index dae2f8dbf84294b3c88c98d8119a0dd96024c9f7..2b354b92f054798664063deec32f60b59103baf2 100644 (file)
@@ -19,7 +19,7 @@ $chip-tokens: defaults(
     --chip-dismiss-size: 1rem,
     --chip-dismiss-opacity: .65,
     --chip-dismiss-hover-opacity: 1,
-    --chip-color: var(--theme-text, var(--fg-body)),
+    --chip-color: var(--theme-fg, var(--fg-body)),
     --chip-bg: var(--theme-bg-subtle, var(--bg-2)),
     --chip-border-color: transparent,
     --chip-selected-color: var(--theme-contrast, var(--primary-contrast)),
index 5fbc2411d01cb34cc9429b3fd4aa78f6b45eb3a3..acc59cd03c1f05bb753d9c6417e78ab8dc2d82d4 100644 (file)
@@ -65,7 +65,7 @@ $list-group-tokens: defaults(
     position: relative;
     display: block;
     padding: var(--list-group-item-padding-y) var(--list-group-item-padding-x);
-    color: var(--theme-text, var(--list-group-color));
+    color: var(--theme-fg, var(--list-group-color));
     // stylelint-disable-next-line scss/at-function-named-arguments
     text-decoration: if(sass($link-decoration == none): null);
     background-color: var(--theme-bg-subtle, var(--list-group-bg));
@@ -112,7 +112,7 @@ $list-group-tokens: defaults(
 
   .list-group-item-action {
     width: 100%; // For `<button>`s (anchors become 100% by default though)
-    color: var(--theme-text, var(--list-group-action-color));
+    color: var(--theme-fg, var(--list-group-action-color));
     text-align: inherit; // For `<button>`s (anchors inherit)
     text-decoration: none;
 
@@ -121,13 +121,13 @@ $list-group-tokens: defaults(
       &:hover,
       &:focus {
         z-index: 1; // Place hover/focus items above their siblings for proper border styling
-        color: var(--theme-text-emphasis, var(--list-group-action-hover-color));
+        color: var(--theme-fg-emphasis, var(--list-group-action-hover-color));
         text-decoration: none;
         background-color: var(--theme-bg-muted, var(--list-group-action-hover-bg));
       }
 
       &:active {
-        color: var(--theme-text-emphasis, var(--list-group-action-active-color));
+        color: var(--theme-fg-emphasis, var(--list-group-action-active-color));
         background-color: var(--theme-bg-muted, var(--list-group-action-active-bg));
       }
     }
index 3b4432a87aa20cd11572bd0dc38aa052a34703b9..ed12970911a552ca59c90dc771ea9691180313b2 100644 (file)
@@ -152,7 +152,7 @@ $menu-tokens: defaults(
     width: 100%;
     padding: var(--menu-item-padding-y) var(--menu-item-padding-x);
     font-weight: var(--menu-item-font-weight, var(--font-weight-normal));
-    color: var(--theme-text, var(--menu-item-color));
+    color: var(--theme-fg, var(--menu-item-color));
     text-align: inherit;
     text-decoration: none;
     white-space: nowrap;
@@ -164,7 +164,7 @@ $menu-tokens: defaults(
 
     &:hover,
     &:focus {
-      color: var(--theme-text-emphasis, var(--menu-item-hover-color));
+      color: var(--theme-fg-emphasis, var(--menu-item-hover-color));
       background-color: var(--theme-bg-subtle, var(--menu-item-hover-bg));
       // @include gradient-bg(var(--theme-bg-subtle, var(--menu-item-hover-bg)));
     }
index 7a89c16ad15dbd17974c307cf406ee9613af47e2..f8040e9591a22c46f722736b086c85cc10962537 100644 (file)
@@ -41,7 +41,7 @@ $root-tokens: defaults(
 
     --hr-border-color: var(--border-color),
 
-    --link-color: light-dark(var(--primary-base), var(--primary-text)),
+    --link-color: light-dark(var(--primary-base), var(--primary-fg)),
     --link-decoration: #{$link-decoration},
     --link-hover-color: color-mix(in oklch, var(--link-color) 90%, #000),
 
index d2b3ee6b6213a4b480e6ff6738d401c3aaf9d488..1c79e19e72e678ad4ba2d1e01ab8013fe1f0d37d 100644 (file)
   @return $result;
 }
 
+// Themes map sub-keys
+//
+// Return var() references to root tokens instead of raw values.
+// Ex: theme-color-refs("bg") => (primary: var(--primary-bg), accent: var(--accent-bg), ...)
+@function theme-color-refs($key) {
+  $result: ();
+
+  @each $color-name, $color-map in $theme-colors {
+    @if map.has-key($color-map, $key) {
+      $result: map.merge($result, ($color-name: var(--#{$color-name}-#{$key})));
+    }
+  }
+
+  @return $result;
+}
+
+// Theme token to root tokens
+//
+// Returns the global :root token reference for a given a given token map, prefix, and key.
+// Ex: theme-token-refs($theme-bgs, "bg") => (body: var(--bg-body), 1: var(--bg-1), ...)
+// Skips `inherit` since it's a CSS-wide keyword that can't be stored in a custom property.
+@function theme-token-refs($map, $prefix) {
+  $result: ();
+
+  @each $key, $value in $map {
+    @if $value != inherit {
+      $result: map.merge($result, ($key: var(--#{$prefix}-#{$key})));
+    }
+  }
+
+  @return $result;
+}
+
 // Generate opacity values using color-mix()
 @function theme-opacity-values($color-var, $opacities: $util-opacity) {
   $result: ();
@@ -45,8 +78,8 @@
 $theme-colors: (
   "primary": (
     "base": var(--blue-500),
-    "text": light-dark(var(--blue-600), var(--blue-400)),
-    "text-emphasis": light-dark(var(--blue-800), var(--blue-200)),
+    "fg": light-dark(var(--blue-600), var(--blue-400)),
+    "fg-emphasis": light-dark(var(--blue-800), var(--blue-200)),
     "bg": var(--blue-500),
     "bg-subtle": light-dark(var(--blue-100), var(--blue-900)),
     "bg-muted": light-dark(var(--blue-200), var(--blue-800)),
@@ -56,8 +89,8 @@ $theme-colors: (
   ),
   "accent": (
     "base": var(--indigo-500),
-    "text": light-dark(var(--indigo-600), color-mix(in oklch, var(--indigo-400), var(--indigo-300))),
-    "text-emphasis": light-dark(var(--indigo-800), var(--indigo-300)),
+    "fg": light-dark(var(--indigo-600), color-mix(in oklch, var(--indigo-400), var(--indigo-300))),
+    "fg-emphasis": light-dark(var(--indigo-800), var(--indigo-300)),
     "bg": var(--indigo-500),
     "bg-subtle": light-dark(var(--indigo-100), var(--indigo-900)),
     "bg-muted": light-dark(var(--indigo-200), var(--indigo-800)),
@@ -67,8 +100,8 @@ $theme-colors: (
   ),
   "success": (
     "base": var(--green-500),
-    "text": light-dark(var(--green-600), var(--green-400)),
-    "text-emphasis": light-dark(var(--green-800), var(--green-300)),
+    "fg": light-dark(var(--green-600), var(--green-400)),
+    "fg-emphasis": light-dark(var(--green-800), var(--green-300)),
     "bg": var(--green-500),
     "bg-subtle": light-dark(var(--green-100), var(--green-900)),
     "bg-muted": light-dark(var(--green-200), var(--green-800)),
@@ -78,8 +111,8 @@ $theme-colors: (
   ),
   "danger": (
     "base": var(--red-500),
-    "text": light-dark(var(--red-600), var(--red-400)),
-    "text-emphasis": light-dark(var(--red-800), var(--red-300)),
+    "fg": light-dark(var(--red-600), var(--red-400)),
+    "fg-emphasis": light-dark(var(--red-800), var(--red-300)),
     "bg": var(--red-500),
     "bg-subtle": light-dark(var(--red-100), var(--red-900)),
     "bg-muted": light-dark(var(--red-200), var(--red-800)),
@@ -89,8 +122,8 @@ $theme-colors: (
   ),
   "warning": (
     "base": var(--yellow-500),
-    "text": light-dark(var(--yellow-700), var(--yellow-400)),
-    "text-emphasis": light-dark(var(--yellow-800), var(--yellow-300)),
+    "fg": light-dark(var(--yellow-700), var(--yellow-400)),
+    "fg-emphasis": light-dark(var(--yellow-800), var(--yellow-300)),
     "bg": var(--yellow-500),
     "bg-subtle": light-dark(var(--yellow-100), var(--yellow-900)),
     "bg-muted": light-dark(var(--yellow-200), var(--yellow-800)),
@@ -100,8 +133,8 @@ $theme-colors: (
   ),
   "info": (
     "base": var(--cyan-500),
-    "text": light-dark(var(--cyan-600), var(--cyan-400)),
-    "text-emphasis": light-dark(var(--cyan-800), var(--cyan-300)),
+    "fg": light-dark(var(--cyan-600), var(--cyan-400)),
+    "fg-emphasis": light-dark(var(--cyan-800), var(--cyan-300)),
     "bg": var(--cyan-500),
     "bg-subtle": light-dark(var(--cyan-100), var(--cyan-900)),
     "bg-muted": light-dark(var(--cyan-200), var(--cyan-800)),
@@ -111,8 +144,8 @@ $theme-colors: (
   ),
   "inverse": (
     "base": var(--gray-900),
-    "text": light-dark(var(--gray-900), var(--gray-200)),
-    "text-emphasis": light-dark(var(--gray-975), var(--white)),
+    "fg": light-dark(var(--gray-900), var(--gray-200)),
+    "fg-emphasis": light-dark(var(--gray-975), var(--white)),
     "bg": light-dark(var(--gray-900), var(--gray-025)),
     "bg-subtle": light-dark(var(--gray-100), var(--gray-900)),
     "bg-muted": light-dark(var(--gray-200), var(--gray-300)),
@@ -122,8 +155,8 @@ $theme-colors: (
   ),
   "secondary": (
     "base": var(--gray-200),
-    "text": light-dark(var(--gray-600), var(--gray-400)),
-    "text-emphasis": light-dark(var(--gray-800), var(--gray-200)),
+    "fg": light-dark(var(--gray-600), var(--gray-400)),
+    "fg-emphasis": light-dark(var(--gray-800), var(--gray-200)),
     "bg": light-dark(var(--gray-100), var(--gray-600)),
     "bg-subtle": light-dark(var(--gray-050), var(--gray-800)),
     "bg-muted": light-dark(var(--gray-100), var(--gray-700)),
index 80981f5f7bd00b30e150270cad52735477969c31..97aba6950d774e5689c1e595fe0bf07525a29430 100644 (file)
@@ -76,7 +76,7 @@ $toast-tokens: defaults(
     display: flex;
     align-items: center;
     padding: var(--toast-padding-y) var(--toast-padding-x);
-    color: var(--theme-text-emphasis, var(--toast-header-color));
+    color: var(--theme-fg-emphasis, var(--toast-header-color));
     background-color: var(--theme-bg-subtle, var(--toast-header-bg));
     // background-clip: padding-box;
     border-block-end: var(--toast-border-width, var(--border-width)) solid var(--theme-border, var(--toast-header-border-color, var(--border-color-translucent)));
index 533ad3a43039ecf37b26bcc4eb9a99dd5b6c58be..9b8af3b7c12758356b70568ff8d5ea0114d86555 100644 (file)
@@ -217,7 +217,7 @@ $utilities: map.merge(
         "border-color": var(--border-color)
       ),
       class: border,
-      values: map.merge(theme-color-values("bg"), $theme-borders),
+      values: map.merge(theme-color-refs("bg"), theme-token-refs($theme-borders, "border")),
     ),
     "border-color-subtle": (
       property: (
@@ -225,7 +225,7 @@ $utilities: map.merge(
         "border-color": var(--border-color)
       ),
       class: border-subtle,
-      values: theme-color-values("border"),
+      values: theme-color-refs("border"),
     ),
     "border-width": (
       property: border-width,
@@ -729,7 +729,7 @@ $utilities: map.merge(
         "color": var(--fg)
       ),
       class: fg,
-      values: map.merge(theme-color-values("text"), $theme-fgs),
+      values: map.merge(theme-color-refs("fg"), theme-token-refs($theme-fgs, "fg")),
     ),
     "fg-emphasis": (
       property: (
@@ -737,7 +737,7 @@ $utilities: map.merge(
         "color": var(--fg)
       ),
       class: fg-emphasis,
-      values: theme-color-values("text-emphasis"),
+      values: theme-color-refs("fg-emphasis"),
     ),
     "fg-contrast": (
       property: (
@@ -745,7 +745,7 @@ $utilities: map.merge(
         "color": var(--fg)
       ),
       class: fg-contrast,
-      values: theme-color-values("contrast"),
+      values: theme-color-refs("contrast"),
     ),
     "fg-opacity": (
       class: fg,
@@ -776,7 +776,7 @@ $utilities: map.merge(
     "underline-color": (
       property: text-decoration-color,
       class: underline,
-      values: theme-color-values("text"),
+      values: theme-color-values("fg"),
     ),
     "underline-opacity": (
       property: text-decoration-color,
@@ -804,7 +804,7 @@ $utilities: map.merge(
         "background-color": var(--bg)
       ),
       class: bg,
-      values: map.merge(theme-color-values("bg"), $theme-bgs),
+      values: map.merge(theme-color-refs("bg"), theme-token-refs($theme-bgs, "bg")),
     ),
     "bg-color-subtle": (
       property: (
@@ -812,7 +812,7 @@ $utilities: map.merge(
         "background-color": var(--bg)
       ),
       class: bg-subtle,
-      values: theme-color-values("bg-subtle"),
+      values: theme-color-refs("bg-subtle"),
     ),
     "bg-color-muted": (
       property: (
@@ -820,7 +820,7 @@ $utilities: map.merge(
         "background-color": var(--bg)
       ),
       class: bg-muted,
-      values: theme-color-values("bg-muted"),
+      values: theme-color-refs("bg-muted"),
     ),
     "bg-opacity": (
       class: bg,
@@ -841,7 +841,7 @@ $utilities: map.merge(
     "theme-subtle": (
       property: (
         "background-color": var(--theme-bg-subtle),
-        "color": var(--theme-text)
+        "color": var(--theme-fg)
       ),
       class: theme-subtle,
       values: (null: null)
@@ -849,7 +849,7 @@ $utilities: map.merge(
     "theme-muted": (
       property: (
         "background-color": var(--theme-bg-muted),
-        "color": var(--theme-text-emphasis)
+        "color": var(--theme-fg-emphasis)
       ),
       class: theme-muted,
       values: (null: null)
index 8acf19f8792cc2f97ae7ef83bb9514d8d601226a..4435e2e08c6d2f9da9f32d75e8f51fe27dca03b3 100644 (file)
@@ -321,7 +321,7 @@ $btn-variant-selectors: (string.unquote(".btn"), string.unquote(".btn-link"), st
   .btn-link {
     @include tokens($button-link-tokens);
 
-    color: var(--theme-text, var(--btn-color));
+    color: var(--theme-fg, var(--btn-color));
     text-decoration: var(--link-decoration);
 
     @if $enable-gradients {
@@ -329,11 +329,11 @@ $btn-variant-selectors: (string.unquote(".btn"), string.unquote(".btn-link"), st
     }
 
     &:focus-visible {
-      color: var(--theme-text, var(--btn-color));
+      color: var(--theme-fg, var(--btn-color));
     }
 
     &:hover {
-      color: var(--theme-text-emphasis, var(--btn-hover-color));
+      color: var(--theme-fg-emphasis, var(--btn-hover-color));
     }
 
     // No need for an active state here
index 7e2eaab30d1da5445052dd3e20f59d7238525f6c..0408e9baaa20fb56e7eeed4b08b764a54b9937f2 100644 (file)
@@ -10,7 +10,8 @@ $prose-tokens: () !default;
 $prose-tokens: defaults(
   (
     --content-font-size: 1rem,
-    --content-gap: 20px,
+    --content-line-height: 1.5,
+    --content-gap: calc(var(--content-font-size) * var(--content-line-height)),
     --heading-color: light-dark(var(--gray-900), var(--white)),
   ),
   $prose-tokens
@@ -28,11 +29,12 @@ $prose-tokens: defaults(
     max-width: 1000px;
     margin-inline: auto;
     font-size: var(--content-font-size);
-    line-height: 1.5;
+    line-height: var(--content-line-height);
 
     @media (width >= 1024px) {
       --content-font-size: var(--font-size-md);
-      --content-gap: 24px;
+      --content-line-height: 1.625;
+      // --content-gap: calc(var(--content-font-size) * var(--content-line-height));
     }
 
     :where(p, ul, ol, dl, pre, table, blockquote):not(:where(.not-prose, .not-prose *)) {
index 01ee4545fbdc61de889ec396dea4268f8c109447..806e7b02e19504a28d41ac6c218197f175e18335 100644 (file)
@@ -267,14 +267,14 @@ $reboot-mark-tokens: defaults(
   // Links
 
   a {
-    color: var(--theme-text, var(--link-color));
+    color: var(--theme-fg, var(--link-color));
     text-decoration: var(--link-decoration);
     text-underline-offset: $link-underline-offset;
 
     &:hover {
       // --link-color: var(--link-hover-color);
       // --link-decoration: var(--link-hover-decoration, var(--link-decoration));
-      color: var(--theme-text-emphasis, var(--link-hover-color));
+      color: var(--theme-fg-emphasis, var(--link-hover-color));
       text-decoration: var(--link-hover-decoration, var(--link-decoration));
     }
   }
index cda6190cfa2af6f0b3764c351455914e3e41987d..de6bf0cf226401e0caec32cc33d5366256caa74a 100644 (file)
@@ -66,7 +66,7 @@ $table-striped-columns-order: even !default;
     > :not(caption) > * > * {
       padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
       // Following the precept of cascades: https://codepen.io/miriamsuzanne/full/vYNgodb
-      color: var(--table-color-state, var(--table-color-type, var(--theme-text, var(--table-color))));
+      color: var(--table-color-state, var(--table-color-type, var(--theme-fg, var(--table-color))));
       background-color: var(--theme-bg-subtle, var(--table-bg));
       border-block-end-width: var(--table-border-width);
       box-shadow: inset 0 0 0 9999px var(--table-bg-state, var(--table-bg-type, var(--theme-bg-subtle, var(--table-accent-bg))));
@@ -143,16 +143,16 @@ $table-striped-columns-order: even !default;
   // For rows
   .table-striped {
     > tbody > tr:nth-of-type(#{$table-striped-order}) > * {
-      --table-color-type: var(--theme-text, var(--table-striped-color));
-      --table-bg-type: color-mix(in srgb, var(--theme-text, var(--table-color)) var(--table-striped-bg-factor), transparent);
+      --table-color-type: var(--theme-fg, var(--table-striped-color));
+      --table-bg-type: color-mix(in srgb, var(--theme-fg, var(--table-color)) var(--table-striped-bg-factor), transparent);
     }
   }
 
   // For columns
   .table-striped-columns {
     > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) {
-      --table-color-type: var(--theme-text, var(--table-striped-color));
-      --table-bg-type: color-mix(in srgb, var(--theme-text, var(--table-color)) var(--table-striped-bg-factor), transparent);
+      --table-color-type: var(--theme-fg, var(--table-striped-color));
+      --table-bg-type: color-mix(in srgb, var(--theme-fg, var(--table-color)) var(--table-striped-bg-factor), transparent);
     }
   }
 
@@ -161,8 +161,8 @@ $table-striped-columns-order: even !default;
   // The `.table-active` class can be added to highlight rows or cells
 
   .table-active {
-    --table-color-state: var(--theme-text, var(--table-active-color));
-    --table-bg-state: color-mix(in srgb, var(--theme-text, var(--table-color)) var(--table-active-bg-factor), transparent);
+    --table-color-state: var(--theme-fg, var(--table-active-color));
+    --table-bg-state: color-mix(in srgb, var(--theme-fg, var(--table-color)) var(--table-active-bg-factor), transparent);
   }
 
   // Hover effect
@@ -171,8 +171,8 @@ $table-striped-columns-order: even !default;
 
   .table-hover {
     > tbody > tr:hover > * {
-      --table-color-state: var(--theme-text, var(--table-hover-color));
-      --table-bg-state: color-mix(in srgb, var(--theme-text, var(--table-color)) var(--table-hover-bg-factor), transparent);
+      --table-color-state: var(--theme-fg, var(--table-hover-color));
+      --table-bg-state: color-mix(in srgb, var(--theme-fg, var(--table-color)) var(--table-hover-bg-factor), transparent);
     }
   }
 
index 3744c2fc265af6cb5952661941d1d7f39242df4b..edfbff244047de83dfdb2fe36c53c12145442831 100644 (file)
@@ -78,7 +78,7 @@ $chip-input-tokens: defaults(
   // @each $color-name, $theme-props in $theme-map {
   //   .chip-input.theme-#{$color-name} > .chip {
   //     // Subtle default state
-  //     --chip-color: var(--theme-text);
+  //     --chip-color: var(--theme-fg);
   //     --chip-bg: var(--theme-bg-subtle);
 
   //     // Selected/active solid state
index c24a20f5aa59c44364324121924417ac45d6f12f..12f322b01933b2a84f70d8d8db3d1cb790dd3c02 100644 (file)
@@ -2,8 +2,8 @@
 $form-feedback-margin-top:          .5rem !default;
 $form-feedback-font-size:           var(--font-size-xs) !default;
 $form-feedback-font-style:          null !default;
-$form-feedback-valid-color:         var(--success-text) !default;
-$form-feedback-invalid-color:       var(--danger-text) !default;
+$form-feedback-valid-color:         var(--success-fg) !default;
+$form-feedback-invalid-color:       var(--danger-fg) !default;
 
 $form-feedback-icon-valid-color:    #00a748 !default;
 $form-feedback-icon-valid:          url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/></svg>") !default;
index f92d53eb3fde597fb7716c45de86dbea86399c83..124b149012ae018eacc05c92fd0637ac71d5b6a2 100644 (file)
@@ -67,7 +67,7 @@ $radio-tokens: defaults(
       --radio-bg: var(--radio-disabled-bg);
 
       ~ label {
-        color: var(--secondary-text);
+        color: var(--secondary-fg);
         cursor: default;
       }
     }
index 8697454144e0fe421831dd50f9db8f8be7f68cc9..3d5db078528474e15155c1687bbce721234b4eb9 100644 (file)
@@ -86,7 +86,7 @@ $switch-tokens: defaults(
       &::before { opacity: .4; }
 
       ~ label {
-        color: var(--secondary-text);
+        color: var(--secondary-fg);
         cursor: default;
       }
     }
index d3a5e18c5332e59f4604fba15f7a18c85e0293b1..d8c44f8b43455a32aa89cf7533fb7554361df7dc 100644 (file)
@@ -15,7 +15,7 @@
       @include output() {
         @include color-mode(dark) {
           .element {
-            color: var(--bs-primary-text-emphasis);
+            color: var(--bs-primary-fg-emphasis);
             background-color: var(--bs-primary-bg-subtle);
           }
         }
@@ -25,7 +25,7 @@
       }
       @include expect() {
         [data-bs-theme=dark] .element {
-          color: var(--bs-primary-text-emphasis);
+          color: var(--bs-primary-fg-emphasis);
           background-color: var(--bs-primary-bg-subtle);
         }
         [data-bs-theme=dark] {
@@ -44,7 +44,7 @@
       @include output() {
         @include color-mode(dark) {
           .element {
-            color: var(--bs-primary-text-emphasis);
+            color: var(--bs-primary-fg-emphasis);
             background-color: var(--bs-primary-bg-subtle);
           }
         }
@@ -55,7 +55,7 @@
       @include expect() {
         @media (prefers-color-scheme: dark) {
           .element {
-            color: var(--bs-primary-text-emphasis);
+            color: var(--bs-primary-fg-emphasis);
             background-color: var(--bs-primary-bg-subtle);
           }
         }
index 0c4830a3b57cf2f3fddebb209b4d3bedf857fccf..94c3bd5231a67f088dc64607e154a8ddf49361cb 100644 (file)
@@ -7,7 +7,7 @@
     --alert-bg: var(--theme-bg-subtle, var(--bg-1)),
     --alert-padding-x: 1rem,
     --alert-padding-y: 1rem,
-    --alert-color: var(--theme-text, inherit),
+    --alert-color: var(--theme-fg, inherit),
     --alert-border-color: var(--theme-border, var(--border-color)),
     --alert-border: var(--border-width) solid var(--alert-border-color),
     --alert-border-radius: var(--border-radius),
index 8051dc416024b8e882e0319430a820801f4e7e5c..a3696436e8f7775140f999fb7b7b1a6575d031d0 100644 (file)
@@ -11,12 +11,12 @@ import { getData } from '@libs/data'
 Cards are flexible and extensible content containers. They include options for headers and footers, a wide variety of content, contextual background colors, and powerful display options. **Cards have no fixed width to start**, so they’ll naturally fill the full width of its parent element, or slot into your grid columns. This is easily customized with our various [sizing options](#width).
 
 <Example code={`<section class="card" style="width: 280px">
+    <Placeholder width="100%" height="180" class="card-img-top" text="Image cap" />
     <div class="card-body">
       <h4 class="card-title">Card title</h4>
       <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card’s content.</p>
       <a href="#" class="btn-solid theme-primary">Go somewhere</a>
     </div>
-    <Placeholder width="100%" height="180" class="card-img-top" text="Image cap" />
   </section>`} />
 
 ## How it works
@@ -334,7 +334,7 @@ Similar to headers and footers, cards can include top and bottom “image caps
 
 Turn an image into a card background and overlay your card’s text. Depending on the image, you may or may not need additional styles or utilities.
 
-<Example code={`<div class="card text-bg-dark">
+<Example code={`<div class="card theme-inverse">
     <Placeholder width="100%" height="270" class="bd-placeholder-img-lg card-img" text="Card image" />
     <div class="card-img-overlay">
       <h4 class="card-title">Card title</h4>
index 9d4a54d10d680fba8107b3ab96abd27cac2c3f85..58aa8c838c6678595d98a232fc8bcfcde1f83def 100644 (file)
@@ -100,7 +100,7 @@ $color-mode-type: data;
 
 @include color-mode(dark) {
   .element {
-    color: var(--bs-primary-text-emphasis);
+    color: var(--bs-primary-fg-emphasis);
     background-color: var(--bs-primary-bg-subtle);
   }
 }
@@ -110,7 +110,7 @@ Outputs to:
 
 ```css
 [data-bs-theme=dark] .element {
-  color: var(--bs-primary-text-emphasis);
+  color: var(--bs-primary-fg-emphasis);
   background-color: var(--bs-primary-bg-subtle);
 }
 ```
@@ -122,7 +122,7 @@ $color-mode-type: media-query;
 
 @include color-mode(dark) {
   .element {
-    color: var(--bs-primary-text-emphasis);
+    color: var(--bs-primary-fg-emphasis);
     background-color: var(--bs-primary-bg-subtle);
   }
 }
@@ -133,7 +133,7 @@ Outputs to:
 ```css
 @media (prefers-color-scheme: dark) {
   .element {
-    color: var(--bs-primary-text-emphasis);
+    color: var(--bs-primary-fg-emphasis);
     background-color: var(--bs-primary-bg-subtle);
   }
 }
@@ -147,8 +147,7 @@ For example, you can create a “blue theme” with the selector `data-bs-theme=
 
 <ScssDocs name="custom-color-mode" file="site/src/scss/_content.scss" />
 
-<Example showMarkup={false} code={`<div data-bs-theme="blue">
-    <div class="bd-example fg-body bg-body">
+<Example showMarkup={false} code={`<div class="p-5 fg-body bg-body rounded-3" data-bs-theme="blue">
       <div class="h4">Example blue theme</div>
       <p>Some paragraph text to show how the blue theme might look with written copy.</p>
 
@@ -167,7 +166,6 @@ For example, you can create a “blue theme” with the selector `data-bs-theme=
           <a class="menu-item" href="#">Separated link</a>
         </div>
       </div>
-    </div>
   </div>`} />
 
 ```html
index be2d46847a380e3d33c575ae4f777471cc8d3b94..29b72cb5085f6b8a050c01e2026e5777931074d1 100644 (file)
@@ -8,8 +8,8 @@ import { getData } from '@libs/data'
 
 export const themeTokens = [
   'base',
-  'text',
-  'text-emphasis',
+  'fg',
+  'fg-emphasis',
   'bg',
   'bg-subtle',
   'bg-muted',
@@ -65,10 +65,10 @@ And within each semantic theme color, you'll find the following keys, most of wh
 | Theme token | Description |
 | --- | --- |
 | `base` | The default color value for the semantic color |
-| `text` | Accessible text color (against body, plus `subtle` and `muted` color tokens) |
-| `text-emphasis` | Emphasized text color for use with `muted` background tokens |
+| `fg` | Accessible text color (against body, plus `subtle` and `muted` color tokens) |
+| `fg-emphasis` | Emphasized text color for use with `muted` background tokens |
 | `bg` | For solid colored backgrounds with high contrast |
-| `bg-subtle` | Lowest contrast backgrounds, usually paired with `text` key for text color |
+| `bg-subtle` | Lowest contrast backgrounds, usually paired with `fg` key for text color |
 | `bg-muted` | Lower contrast backgrounds, often used for disabled states |
 | `border` | Borders and dividers |
 | `focus-ring` | For visible focus indicators and outline styles |
@@ -100,18 +100,18 @@ Every token is available as a CSS variable, and most are then consumed by our ut
 Not all colors can be used for all purposes due to accessibility, color contrast, and general aesthetic considerations. Here are some recommended pairings.
 
 - `contrast` work best with `bg`
-- `text` works best with `subtle`
-- `text-emphasis` works best with `muted`
+- `fg` works best with `subtle`
+- `fg-emphasis` works best with `muted`
 - `border` works best with `subtle`, but can be used with `muted`
 
 <Example code={`<div class="theme-primary vstack gap-3">
     <div style="color: var(--bs-theme-contrast); background: var(--bs-theme-bg);" class="p-3 rounded-3">
       Example element with theme color
     </div>
-    <div style="color: var(--bs-theme-text-emphasis); background: var(--bs-theme-bg-muted); border: 1px solid var(--bs-theme-border);" class="p-3 rounded-3">
+    <div style="color: var(--bs-theme-fg-emphasis); background: var(--bs-theme-bg-muted); border: 1px solid var(--bs-theme-border);" class="p-3 rounded-3">
       Example element with theme color
     </div>
-    <div style="color: var(--bs-theme-text); background: var(--bs-theme-bg-subtle); border: 1px solid var(--bs-theme-border);" class="p-3 rounded-3">
+    <div style="color: var(--bs-theme-fg); background: var(--bs-theme-bg-subtle); border: 1px solid var(--bs-theme-border);" class="p-3 rounded-3">
       Example element with theme color
     </div>
   </div>`} />
@@ -255,10 +255,10 @@ Here's the same set of components rendered in both light and dark modes side by
     </div>
   </div>`} />
 
-Under the hood, token values like `--bs-primary-text` resolve differently depending on the active color mode. For example, in our `_theme.scss`, the primary text color is defined as:
+Under the hood, token values like `--bs-primary-fg` resolve differently depending on the active color mode. For example, in our `_theme.scss`, the primary text color is defined as:
 
 ```scss
-"text": light-dark(var(--blue-600), var(--blue-400)),
+"fg": light-dark(var(--blue-600), var(--blue-400)),
 ```
 
 When `data-bs-theme="light"` is active (or the user's system preference is light), this resolves to `var(--blue-600)`. In dark mode, it resolves to `var(--blue-400)`—a lighter shade that maintains readability against dark backgrounds. The same pattern applies to backgrounds, borders, and all other adaptive tokens.
index f18c775d7868cc9689615e393409662864f4ffd5..3b73b88a4959a1d52f674b2a7e744abeb76c737f 100644 (file)
@@ -6,7 +6,14 @@ toc: true
 
 ## Sass & CSS
 
-Bootstrap 6 has a new philosophy of using Sass and CSS together to customize the project for your needs. At a high level, **Sass is for programmatic customization** and **CSS variables are for visual customization**. Previous iterations have treated Sass as both programmatic and visual customization with CSS variables adding a more complicated secondary layer. This has been greatly improved in v6.
+Bootstrap 6 brings with it a new philosophy of using Sass and CSS together to build and customize projects for your specific needs. At a high level:
+
+- **Sass is for programmatic configuration —** Think functions, loops, mixins, and more for generative constructs.
+- **CSS is for visual customization —** CSS variables for visual properties like colors, spacing, typography, etc.
+
+Previous major versions have treated Sass as both programmatic and visual customization with CSS variables adding a more complicated, and less complete, secondary layer. This has been greatly improved in v6.
+
+On top of that, we use [PostCSS](https://postcss.org/) to prefix our CSS variables with the `bs-` prefix and add vendor prefixes to our CSS properties, as appropriate.
 
 ### Sass
 
@@ -31,7 +38,24 @@ While you can use Sass to customize how Bootstrap looks, the preferred way now i
 
 ### Examples
 
-Here's how we'd use a mix of Sass and CSS to customize Bootstrap. The Sass helps us manage features and gives us access to generative tokens, while the CSS allows us to customize individual tokens and values.
+Here's how we'd use a mix of Sass and CSS to customize Bootstrap. The Sass helps us manage features and gives us access to generative tokens, while the CSS allows us to customize individual tokens and values. In almost all our components, we setup a Sass map of "tokens" that are really just CSS variables. Using this map, we then generate the CSS custom properties on the component's class.
+
+For example, the alert component has a `$alert-tokens` map that is used to generate the CSS custom properties on the `.alert` class.
+
+```scss
+$alert-tokens: (
+  --alert-padding-x: 2rem,
+  --alert-border-radius: 1rem,
+  // …
+);
+
+.alert {
+  @include tokens($alert-tokens);
+  // …
+}
+```
+
+In practice for you and your projects, this means you can use Sass's module system to override the CSS variables at build-time for a specific component, or even globally.
 
 ```scss
 @use "../node_modules/bootstrap/scss/bootstrap" with (
@@ -82,10 +106,10 @@ Bootstrap employs a handful of important global styles and settings geared towar
 
 ### Responsive design
 
-Responsive web design is the practice of building a website that responds to the viewport size of the device it's being viewed on. This is achieved by using media queries to apply different styles to the website based on the viewport size.
+Responsive web design is the practice of building a website that responds to the viewport size of the device it's being viewed on. This is achieved by using range media queries to apply different styles to the website based on the viewport size.
 
 ```css
-@media (max-width: 768px) {
+@media (width < 768px) {
   .container {
     max-width: 100%;
   }
@@ -99,9 +123,9 @@ Bootstrap ships with several responsive tiers or breakpoints that allow you to s
 Bootstrap requires the use of the HTML5 doctype. Without it, you’ll see some funky and incomplete styling.
 
 ```html
-<!doctype html>
+<!doctype html><!--[!code highlight]-->
 <html lang="en">
-  ...
+  …
 </html>
 ```
 
@@ -110,7 +134,16 @@ Bootstrap requires the use of the HTML5 doctype. Without it, you’ll see some f
 Bootstrap is developed *mobile first*, a strategy in which we optimize code for mobile devices first and then scale up components as necessary using CSS media queries. To ensure proper rendering and touch zooming for all devices, add the responsive viewport meta tag to your `<head>`.
 
 ```html
-<meta name="viewport" content="width=device-width, initial-scale=1">
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta name="viewport" content="width=device-width, initial-scale=1"><!--[!code highlight]-->
+    …
+  </head>
+  <body>
+    …
+  </body>
+</html>
 ```
 
 You can see an example of this in action in [the quick start]([[docsref:/guides/quickstart/]]).
@@ -135,7 +168,7 @@ For improved cross-browser rendering, we use [Reboot]([[docsref:/content/reboot]
 
 ### Browser support
 
-You can find our supported range of browsers and their versions [in our `.browserslistrc file`]([[config:repo]]/blob/v[[config:current_version]]/.browserslistrc):
+You can find our supported range of browsers and their versions [in our `.browserslistrc` file]([[config:repo]]/blob/v[[config:current_version]]/.browserslistrc):
 
 <Code lang="plaintext" filePath=".browserslistrc" />
 
@@ -154,6 +187,8 @@ Beyond what Bootstrap does, here's *why* we do it—our philosophy for building
 - Use utilities over custom styles
 - Avoid enforcing strict HTML requirements (immediate children selectors)
 
+These rules cannot always be followed to the letter, but we strive to follow them as much as possible.
+
 ### Responsive
 
 Bootstrap's styles are mobile-first—we add styles as the viewport grows rather than overriding them as it shrinks. Not every component must be fully responsive, but this approach reduces CSS overrides.
@@ -181,7 +216,7 @@ Some components in Bootstrap are built with overlapping elements to prevent doub
 
 Components built with overlays also have a predefined z-index scale, beginning at `1000`. This starting number was chosen arbitrarily and serves as a small buffer between our styles and your project’s custom styles.
 
-<ScssDocs name="zindex-stack" file="scss/_config.scss" />
+<ScssDocs name="zindex-levels-map" file="scss/_config.scss" />
 
 Each overlay component increases its `z-index` value slightly in such a way that common UI principles allow user focused or hovered elements to remain in view at all times. For example, a modal is document blocking (e.g., you cannot take any other action save for the modal’s action), so we put that above our navbars.
 
index 5f64637e81b234e8cbafddb45dbc45c28392bd78..da4f9fbd0d2ca82c01d60d2340daaf5411fa4a82 100644 (file)
@@ -10,10 +10,12 @@ aliases:
 
 ## Install
 
-Pull in Bootstrap’s **source files** into nearly any project with some of the most popular package managers. No matter the package manager, Bootstrap will **require a [Sass compiler]([[docsref:/guides/contribute#sass]]) and [Autoprefixer](https://github.com/postcss/autoprefixer)** for a setup that matches our official compiled versions.
+Pull in Bootstrap’s **source files** into nearly any project with some of the most popular package managers. No matter the package manager, Bootstrap will **require a [Sass compiler]([[docsref:/guides/contribute#sass]]) and [PostCSS](https://github.com/postcss/postcss)** for a setup that matches our official compiled versions.
 
 Package managed installs don't include documentation or our full build scripts. You can also [use any demo from our Examples repo](https://github.com/twbs/examples) to quickly jumpstart Bootstrap projects.
 
+After installing, head to [our npm guide]([[docsref:/guides/npm]]) for a full setup guide.
+
 <Code
   tabs={[
     { label: 'npm', code: 'npm install bootstrap', lang: 'bash' },
index 0c65283f4f9f9c7f93353bd307786ef27a5b484d..e26a500364232a45a6e7cdc2be08cd32135f8359 100644 (file)
@@ -50,10 +50,10 @@ Bootstrap 6 is a major release with many breaking changes to modernize our codeb
 
 ### CSS
 
+- **Clarified and simplified CSS-Sass setup.** Read more about our [approach]([[docsref:/getting-started/approach]]) for how we use Sass and CSS together to build and customize projects for your specific needs, in particular how we use CSS variables inside Sass maps as our first-class customization layer.
 - **Implemented CSS layers** in `_root.scss` and applied them to all our Sass files.
   - Layers are set in `_root.scss` and then utilized across separate Sass partials.
   - We cannot, unfortunately, wrap `@use` or `@forward` statements in `@layer`—Sass expects those to be top level at all times. Also, while CSS allows `@import "file.css" layer(name)`, Sass also does not support that.
-- Clarified and simplified CSS-Sass setup.
 - New, streamlined color modes and theming.
   - Removed `_maps.scss`
   - Removed `_variables-dark.scss`
@@ -66,7 +66,7 @@ Bootstrap 6 is a major release with many breaking changes to modernize our codeb
   - Renamed `xxl` to `2xl` for better scaling with additional custom breakpoints
   - Increased the `2xl` breakpoint from 1400px to 1536px, and it's container from 1320px to 1440px.
 - **Adopted modern CSS color functions.** All Sass color variables now use `oklch()` notation (e.g., `$blue: oklch(60% 0.24 240)`) and tint/shade scales are generated with `color-mix(in lab, ...)` in the compiled CSS. The v5 `$*-rgb` CSS custom properties and `rgba()` patterns have been removed. This requires browser support for `color-mix()` and `oklch()`.
-- **New theme token system with `.theme-*` classes.** Per-component color variant classes (like `.alert-primary`, `.badge.bg-primary`, `.btn-primary`) are replaced by a composable `.theme-{name}` pattern. Adding `.theme-primary` to a component sets `--theme-bg`, `--theme-text`, `--theme-border`, `--theme-contrast`, and other semantic CSS custom properties that the component reads. This applies across buttons, badges, alerts, cards, accordions, and more.
+- **New theme token system with `.theme-*` classes.** Per-component color variant classes (like `.alert-primary`, `.badge.bg-primary`, `.btn-primary`) are replaced by a composable `.theme-{name}` pattern. Adding `.theme-primary` to a component sets `--theme-bg`, `--theme-fg`, `--theme-border`, `--theme-contrast`, and other semantic CSS custom properties that the component reads. This applies across buttons, badges, alerts, cards, accordions, and more.
 - **Responsive and state classes now use a prefix instead of an infix or suffix.** Class names follow the Tailwind-style `prefix:class` pattern (e.g., `md:d-none` instead of `d-md-none`, `hover:opacity-50` instead of `opacity-50-hover`). In HTML, use the unescaped colon: `class="md:d-none"`. This applies to utilities, grid, pseudo-state variants, and all responsive components.
 
 <BsTable>
index 74264a4c1572514d4b285954c7d58dd05a7a14b5..468275ef9148a1aef2c0ad84a4c74363e0c48350 100644 (file)
@@ -192,7 +192,7 @@ $utilities: (
     class: striped,
     child-selector: "> :nth-child(odd)",
     values: (
-      null: var(--bs-tertiary-bg),
+      null: var(--bs-bg-1),
     )
   )
 );
@@ -201,7 +201,7 @@ $utilities: (
 Output:
 
 ```css
-:where(.striped > :nth-child(odd)) { background-color: var(--bs-tertiary-bg); }
+:where(.striped > :nth-child(odd)) { background-color: var(--bs-bg-1); }
 ```
 
 Or target all direct children with `> *`:
index b97f30b1e6ccf0e856b46332d6249df7649224b7..5222438fe26936819a62a64be1ea06088b56c2f5 100644 (file)
@@ -17,13 +17,13 @@ import { getData } from '@libs/data'
 
 ## Colors
 
-Change the `background-color` using utilities built on our theme colors using `.bg-{color}`, `.bg-muted-{color}`, and `.bg-subtle-{color}`. All these background color utilities set the `background-color` property to a local CSS variable, `--bs-bg`, which has the value of the theme color. Most color values also use `light-dark()` to ensure sufficient contrast in both light and dark color modes.
+Change the `background-color` using utilities built on our theme colors using `.bg-{color}`, `.bg-muted-{color}`, and `.bg-subtle-{color}`. All these background color utilities set the `background-color` property to a local CSS variable, `--bs-bg`, which has the value of the theme color. The root color tokens also use `light-dark()` to ensure sufficient contrast in both light and dark color modes.
 
-For example, `.bg-primary` sets the `--bs-bg` variable to `var(--bs-primary-500)`:
+For example, `.bg-primary` sets the `--bs-bg` variable to `var(--bs-primary-bg)`:
 
 ```css
 .bg-primary {
-  --bs-bg: var(--bs-primary-500);
+  --bs-bg: var(--bs-primary-bg);
   background-color: var(--bs-bg);
 }
 ```
@@ -70,6 +70,13 @@ Change the opacity of a background color by using any of the `.bg-<percentage>`
 <div class="bg-success p-2 text-dark bg-20">This is 20% opacity success background</div>
 <div class="bg-success p-2 text-dark bg-10">This is 10% opacity success background</div>`} />
 
+The same can be applied to subtle and muted background colors.
+
+<Example class="d-flex flex-column gap-2" code={`<div class="bg-subtle-success p-2 text-success">This is subtle success background</div>
+<div class="bg-muted-success bg-40 p-2 text-success">This is 40% success background</div>
+<div class="bg-muted-success bg-20 p-2 text-success">This is 20% success background</div>
+`} />
+
 ## CSS
 
 In addition to the following Sass functionality, consider reading about our included [CSS custom properties]([[docsref:/getting-started/css-variables]]) (aka CSS variables) for colors and more.
index d7f77a4ec79eb532706fe392ecd95b52db6f4a54..316f8a02fd51cc1b5fc1415f64e8db12176d5c1e 100644 (file)
@@ -15,13 +15,13 @@ import { getData } from '@libs/data'
 
 ## Colors
 
-Change the `border-color` using utilities built on our theme colors using `.border-{color}` and `.border-subtle-{color}`. All these border color utilities set the `border-color` property to a local CSS variable, `--bs-border-color`, which has the value of the theme color. Color values also use `light-dark()` to ensure sufficient contrast in both light and dark color modes.
+Change the `border-color` using utilities built on our theme colors using `.border-{color}` and `.border-subtle-{color}`. All these border color utilities set the `border-color` property to a local CSS variable, `--bs-border-color`, which has the value of the theme color. The root color tokens color values also use `light-dark()` to ensure sufficient contrast in both light and dark color modes.
 
-For example, `.border-primary` sets the `--bs-border-color` variable to `var(--bs-blue-500)`:
+For example, `.border-primary` sets the `--bs-border-color` variable to `var(--bs-primary-border)`:
 
 ```css
 .border-primary {
-  --bs-border-color: var(--bs-blue-500);
+  --bs-border-color: var(--bs-primary-border);
   border-color: var(--bs-border-color);
 }
 ```
@@ -29,15 +29,15 @@ For example, `.border-primary` sets the `--bs-border-color` variable to `var(--b
 This approach allows us to also easily support translucency with our `.border-{opacity}` utilities as we can use `color-mix()` with the CSS variable to generate the appropriate color. See the [opacity section](#opacity) for more details.
 
 <Example class="d-flex flex-column gap-2 bd-example-border-color-utils" code={[
-  ...getData('theme-colors').map((themeColor) => `<span class="border border-5 border-${themeColor.name}">${themeColor.name}</span>
-<span class="border border-5 border-subtle-${themeColor.name}">${themeColor.name} subtle</span>`),
-  `<span class="border border-5 border-bg">bg</span>
-  <span class="border border-5 border-body">body</span>
-  <span class="border border-5 border-muted">muted</span>
-  <span class="border border-5 border-subtle">subtle</span>
-  <span class="border border-5 border-emphasized">emphasized</span>
-  <span class="border border-5 border-black">black</span>
-<span class="border border-5 border-white">white</span>`
+  ...getData('theme-colors').map((themeColor) => `<div class="border border-5 border-${themeColor.name}">${themeColor.name}</div>
+<div class="border border-5 border-subtle-${themeColor.name}">${themeColor.name} subtle</div>`),
+  `<div class="border border-5 border-bg">bg</div>
+  <div class="border border-5 border-body">body</div>
+  <div class="border border-5 border-muted">muted</div>
+  <div class="border border-5 border-subtle">subtle</div>
+  <div class="border border-5 border-emphasized">emphasized</div>
+  <div class="border border-5 border-black">black</div>
+<div class="border border-5 border-white">white</div>`
 ]} />
 
 Or modify the default `border-color` of a component:
index 085517d80cafb058979af8cf1ae3765ec1f7f1f2..505389b3a6d24bd38c76c0af2b1653ce6a6e4596 100644 (file)
@@ -15,13 +15,13 @@ import { getData } from '@libs/data'
 
 ## Colors
 
-Change the `color` using utilities built on our theme colors using `.fg-{color}` and `.fg-emphasis-{color}`. All these color utilities set the `color` property to a local CSS variable, `--bs-fg`, which has the value of the theme color. Color values also use `light-dark()` to ensure sufficient contrast in both light and dark color modes.
+Change the `color` using utilities built on our theme colors using `.fg-{color}` and `.fg-emphasis-{color}`. All these color utilities set the `color` property to a local CSS variable, `--bs-fg`, which has the value of the theme color. The root color tokens color values also use `light-dark()` to ensure sufficient contrast in both light and dark color modes.
 
-For example, `.fg-primary` sets the `--bs-fg` variable to `light-dark(var(--bs-blue-600), var(--bs-blue-400))`:
+For example, `.fg-primary` sets the `--bs-fg` variable to `var(--bs-primary-fg)`:
 
 ```css
 .fg-primary {
-  --bs-fg: light-dark(var(--bs-blue-600), var(--bs-blue-400));
+  --bs-fg: var(--bs-primary-fg);
   color: var(--bs-fg);
 }
 ```
index 0ddf1e7cd9eea95ee15be580869ddf9af7e829c3..aa76be3a1b4a8c9e93a78099b7c7e437e820b4d2 100644 (file)
@@ -92,12 +92,12 @@ The theme style classes generate the following CSS:
 
 .theme-subtle {
   background-color: var(--theme-bg-subtle);
-  color: var(--theme-text);
+  color: var(--theme-fg);
 }
 
 .theme-muted {
   background-color: var(--theme-bg-muted);
-  color: var(--theme-text-emphasis);
+  color: var(--theme-fg-emphasis);
 }
 ```
 
index 327a256445ae51c5514cd8a54600ecc2d7365fc1..8925c0118ec4738bbae2701a97a152180c9d53d2 100644 (file)
@@ -45,7 +45,7 @@ const canonicalUrl = new URL(Astro.url.pathname, Astro.site)
 
       @media (min-width: 768px) {
         .bd-placeholder-img-lg {
-          font-size: 3.5rem;
+          font-size: 2.5rem;
         }
       }
 
index a8598d46a1c3d95ea06f97f2ccaa0a0315843887..c135cec9f6ecae7cc9c47f09dad9a3effa4b2244 100644 (file)
@@ -170,8 +170,8 @@ function getOptionsWithDefaults(options: Partial<PlaceholderOptions>) {
   const optionsWithDefaults = Object.assign(
     {},
     {
-      background: '#adb5bd',
-      color: '#e9ecef',
+      background: 'var(--bs-bg-2)',
+      color: 'var(--bs-fg-4)',
       height: '180',
       markup: 'svg',
       title: 'Placeholder',
@@ -197,7 +197,7 @@ function getPlaceholderSrc(
   const textColor = color.replace(/^#/, '')
 
   // Build the raw SVG string first
-  let svg = `<svg style='font-size: 1.125rem; font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue","Noto Sans","Liberation Sans",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; -webkit-user-select: none; -moz-user-select: none; user-select: none; text-anchor: middle;' width='200' height='200' xmlns='http://www.w3.org/2000/svg'>`
+  let svg = `<svg style='font-size: 1.125rem; font-family:system-ui; -webkit-user-select: none; -moz-user-select: none; user-select: none; text-anchor: middle;' width='200' height='200' xmlns='http://www.w3.org/2000/svg'>`
 
   if (showTitle) {
     svg += `<title>${title}</title>`
index 9f39430c3bafcf79d7db20ef433195a1b800908e..5fe5b80c5ffbe40f50e5d6fe7f8b23ccb5b01f0c 100644 (file)
@@ -12,7 +12,7 @@
     padding: .25rem .75rem;
     font-size: .8125rem;
     line-height: 1.25rem;
-    color: var(--bs-theme-text, var(--bs-fg-2));
+    color: var(--bs-theme-fg, var(--bs-fg-2));
     background-color: var(--bs-theme-bg-subtle, var(--bs-gray-100));
     @include border-radius(var(--bs-border-radius));
   }
index ee152c3917c56fae8b163b57a6e2676d3b4b5c37..559b11ae1e31cc02a29d60c471ba8afc0c0e5252 100644 (file)
       align-items: center;
       justify-content: center;
       margin-bottom: 1rem;
-      color: var(--bs-secondary-color);
-      background-color: var(--bs-tertiary-bg);
+      color: var(--bs-fg-3);
+      background-color: var(--bs-bg-1);
       border: var(--bs-border-width) solid var(--bs-border-color);
       @include border-radius(var(--bs-border-radius));
     }
       width: 5rem;
       height: 5rem;
       margin: .25rem;
-      background-color: var(--bs-tertiary-bg);
+      background-color: var(--bs-bg-2);
     }
   }
 
index 89c0fde3aa92c942afcd5e5ae01e59566af9086a..94559714bd1abf846a772f2681c1b9c0bd72cb53 100644 (file)
@@ -15,7 +15,7 @@
       margin-bottom: .25rem;
 
       // stylelint-disable selector-max-type, selector-max-compound-selectors
-      > p {
+      > p:not(:first-child) {
         margin-block: 1rem;
       }
 
@@ -61,8 +61,7 @@
       --bs-table-border-color: var(--bs-border-color);
 
       max-width: 100%;
-      margin-bottom: 1.5rem;
-      font-size: .875rem;
+      font-size: var(--bs-font-size-sm);
 
       @include media-breakpoint-down(lg) {
         &.table-bordered {
       }
 
       th {
-        color: var(--bs-emphasis-color);
+        color: var(--bs-fg-body);
         border-block-end-color: currentcolor;
       }
 
       &:not(.bd-callout) > strong { // Keep callout correct color when used within tables
-        color: var(--bs-emphasis-color);
+        color: var(--bs-fg-body);
       }
 
       // Prevent breaking of code
   }
   // stylelint-enable selector-no-qualifying-type
 
-  // stylelint-disable-next-line selector-no-qualifying-type
-  rect[fill="#adb5bd"] {
-    fill: var(--bs-bg-2);
-  }
-  // stylelint-disable-next-line selector-no-qualifying-type
-  text[fill="#e9ecef"] {
-    fill: var(--bs-fg-4);
-  }
-
   // scss-docs-start custom-color-mode
   [data-bs-theme="blue"] {
-    --fg-body: var(--white);
-    --bg-body: var(--blue);
-    --bg-3: var(--blue-600);
+    --bs-fg-body: var(--bs-white);
+    --bs-bg-body: var(--bs-blue-500);
+    --bs-bg-3: var(--bs-blue-600);
+    --bs-hr-border-color: var(--bs-blue-400);
 
     .menu {
-      --menu-bg: color-mix(in lab, var(--blue-500), var(--blue-600));
-      --menu-item-active-bg: var(--blue-700);
+      --bs-menu-bg: color-mix(in lab, var(--bs-blue-600), var(--bs-blue-700));
+      --bs-menu-item-hover-bg: var(--bs-blue-700);
+      --bs-menu-item-active-bg: var(--bs-blue-800);
     }
 
-    .btn-secondary {
-      --btn-bg: color-mix(in lab, var(--gray-600), var(--blue-400));
-      --btn-border-color: color-mix(in lab, var(--fg-body) 25%, transparent);
-      --btn-hover-bg: color-mix(in lab, var(--gray-600), var(--blue-400));
-      --btn-hover-border-color: color-mix(in lab, var(--fg-body) 25%, transparent);
-      --btn-active-bg: color-mix(in lab, color-mix(in lab, var(--gray-600), var(--blue-400)), var(--black) 10%);
-      --btn-active-border-color: color-mix(in lab, var(--fg-body), transparent);
-      --btn-focus-border-color: color-mix(in lab, var(--fg-body), transparent);
-      --btn-focus-box-shadow: 0 0 0 .25rem rgb(255 255 255 / .2);
+    .btn-solid {
+      --bs-btn-bg: color-mix(in lab, var(--bs-gray-600), var(--bs-blue-400));
+      --bs-btn-border-color: color-mix(in lab, var(--bs-fg-body) 25%, transparent);
+      --bs-btn-hover-bg: color-mix(in lab, var(--bs-gray-600), var(--bs-blue-400));
+      --bs-btn-hover-border-color: color-mix(in lab, var(--bs-fg-body) 25%, transparent);
+      --bs-btn-active-bg: color-mix(in lab, color-mix(in lab, var(--bs-gray-600), var(--bs-blue-400)), var(--bs-black) 10%);
+      --bs-btn-active-border-color: color-mix(in lab, var(--bs-fg-body), transparent);
+      --bs-btn-focus-border-color: color-mix(in lab, var(--bs-fg-body), transparent);
+      --bs-btn-focus-box-shadow: 0 0 0 .25rem rgb(255 255 255 / .2);
     }
   }
   // scss-docs-end custom-color-mode
index 8e297804e5418c72ca80b64292af1019dac80fa1..cd43d2647573a87fbd9d060fda9e3fd2625e5df1 100644 (file)
     // stylelint-enable
 
     h1 {
-      --bs-heading-color: var(--bs-emphasis-color);
-      font-size: var(--font-size-4xl);
+      --bs-heading-color: var(--bs-fg-body);
+      font-size: var(--bs-font-size-4xl);
     }
 
     .lead {
       font-size: 1.125rem;
       font-weight: 400;
-      color: var(--bs-secondary-color);
+      color: var(--bs-fg-3);
     }
 
     .bd-code-snippet {
@@ -38,7 +38,7 @@
       overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
-      background-color: color-mix(in oklch, var(--body-color) #{math.percentage(.075)}, transparent);
+      background-color: color-mix(in oklch, var(--bs-fg-body) #{math.percentage(.075)}, transparent);
       @include border-radius(calc(.5rem - 1px));
 
       @include media-breakpoint-up(lg) {
@@ -75,7 +75,7 @@
     h2,
     h3,
     h4 {
-      --bs-heading-color: var(--bs-emphasis-color);
+      --bs-heading-color: var(--bs-fg-body);
     }
 
     .lead {
index ce41536648489226579c2ff115fc9b97d7ad6cc3..6dd8627475bad2fc9cadb23140a19534b10fef75 100644 (file)
@@ -72,7 +72,7 @@
       --menu-min-width: 12rem;
       --menu-padding-x: .25rem;
       --menu-padding-y: .25rem;
-      --menu-item-hover-color: var(--bs-accent-text-emphasis);
+      --menu-item-hover-color: var(--bs-accent-fg-emphasis);
       --menu-item-hover-bg: var(--bs-accent-bg-subtle);
       --menu-item-active-bg: var(--bs-accent-bg);
 
index 3424b2208322e004a83d288e7f260da20f171091..a7c56b4a25619aef3005f6ff45f7d7c9b2c89bcd 100644 (file)
@@ -12,6 +12,6 @@
   }
 
   .bd-placeholder-img-lg {
-    font-size: 3.5rem;
+    font-size: 2.5rem;
   }
 }
index 197b3027e1f1557dc8308beab4bd75391960bcd0..bb627a83239b933fddf21abf61a78d30eb9f8b52 100644 (file)
   }
 }
 
-// .DocSearch-Button {
-//   --docsearch-searchbox-background: transparent;
-//   --docsearch-searchbox-color: var(--bs-color-body);
-//   --docsearch-searchbox-focus-background: var(--bs-bg-2);
-//   --docsearch-searchbox-shadow: none;
-//   --docsearch-text-color: var(--bs-color-body);
-//   --docsearch-muted-color: var(--bs-fg-4);
-
-//   @include media-breakpoint-up(lg) {
-//   display: flex;
-//   align-items: center;
-//   justify-content: center;
-//   width: 100%;
-//   min-width: 38px;
-//   height: 38px;
-//   padding-inline: 12px;
-//   margin-left: 0;
-//   font-weight: var(--bs-font-weight-normal);
-//   color: var(--bs-fg-body);
-//   // border: 1px solid var(--bs-border-subtle);
-//   @include border-radius(var(--bs-border-radius));
-
-//   .DocSearch-Search-Icon {
-//     width: 16px;
-//     height: 16px;
-//   }
-
-//   &:active,
-//   &:focus,
-//   &:hover {
-//     .DocSearch-Search-Icon {
-//       opacity: 1;
-//     }
-//   }
-
-//   @include media-breakpoint-up(md) {
-//     justify-content: space-between;
-//     color: var(--bs-fg-3);
-
-//     .DocSearch-Search-Icon {
-//       opacity: .5;
-//     }
-//   }
-// }
-
-// .DocSearch-Button-Keys,
-// .DocSearch-Button-Placeholder {
-//   @include media-breakpoint-down(lg) {
-//     display: none;
-//   }
-// }
-
-// .DocSearch-Button-Placeholder {
-//   font-size: 14px;
-// }
-
-// .DocSearch-Button-Keys {
-//   display: flex;
-//   gap: 2px;
-//   align-items: center;
-//   min-width: 0;
-//   margin-top: .25rem;
-// }
-
-// .DocSearch-Button-Key {
-//   position: static;
-//   top: 0;
-//   width: auto;
-//   margin: 0;
-//   font-size: var(--bs-font-size-sm);
-//   background: none;
-//   border-radius: 0; // stylelint-disable-line
-//   box-shadow: none;
-// }
-
-// .DocSearch-Commands-Key {
-//   background-image: none;
-//   box-shadow: none;
-// }
-
 .DocSearch-Form {
   @include border-radius(var(--bs-border-radius));
 }
index 33537f80b0e38fb9e4290e6ac9b735f1f58622a0..b2dd711dba75793bf140606c11bf32f3f964829f 100644 (file)
@@ -57,7 +57,7 @@
 
   .bd-links-heading {
     gap: .25rem;
-    color: var(--bs-emphasis-color);
+    color: var(--bs-fg-body);
   }
   .bd-links-heading .bi {
     width: 16px;
index cf7e9f914031613ff2c5b97695c2eca06f5fc487..9f634498daea05a23df085df7360566731d461cd 100644 (file)
@@ -23,6 +23,7 @@
     display: flex;
     flex-direction: column;
     width: fit-content;
+    min-width: 100%;
 
     .line:empty {
       min-height: 1lh;