diff --git a/.changeset/bui-bg-inherit-css-var.md b/.changeset/bui-bg-inherit-css-var.md
new file mode 100644
index 0000000000..214e370c2e
--- /dev/null
+++ b/.changeset/bui-bg-inherit-css-var.md
@@ -0,0 +1,24 @@
+---
+'@backstage/ui': patch
+---
+
+Added a public `--bui-bg-inherit` CSS variable that resolves to the background
+color of the nearest enclosing bg provider (`Box`, `Flex`, `Grid`, `Card`,
+`Accordion`, or any element with a `data-bg` attribute), falling back to
+`--bui-bg-app`. Use it from CSS for sticky or fixed elements that need to match
+their surrounding surface without hardcoding a specific level.
+
+```css
+.searchBarContainer {
+ position: sticky;
+ top: 0;
+ background-color: var(--bui-bg-inherit);
+}
+```
+
+As part of this change, the `data-bg` painting rules previously duplicated in
+`Box`, `Flex`, `Grid`, `Accordion`, and `Card` have been centralized into a
+single source in `core.css`. Painting and component behavior are unchanged for
+all existing usages, with one minor expansion: any element with a `data-bg`
+attribute (including provider elements and any element that sets it directly)
+is now painted, not only `Box`/`Flex`/`Grid`/`Card`/`Accordion` elements.
diff --git a/docs-ui/src/app/tokens/page.mdx b/docs-ui/src/app/tokens/page.mdx
index f359c10525..dbaab30252 100644
--- a/docs-ui/src/app/tokens/page.mdx
+++ b/docs-ui/src/app/tokens/page.mdx
@@ -264,6 +264,42 @@ pressed, and disabled variants for interactive states.
+## Inherited background
+
+`--bui-bg-inherit` resolves to the bg color of the nearest enclosing element with a
+`data-bg` attribute (set by `Box`, `Flex`, `Grid`, `Card`, `Accordion`, or any
+element that explicitly sets `data-bg`). When no such ancestor exists it falls
+back to `--bui-bg-app`. Use it from CSS when a sticky, fixed, or otherwise
+overlapping element needs to match its surrounding bg without hardcoding a level.
+
+
+
+
+
+
+ Prop
+ Description
+
+
+
+
+
+ --bui-bg-inherit
+
+
+ Resolves to the bg color of the nearest enclosing `data-bg` ancestor,
+ falling back to `--bui-bg-app`.
+
+
+
+
+
## Solid background colors
diff --git a/packages/ui/src/components/Accordion/Accordion.module.css b/packages/ui/src/components/Accordion/Accordion.module.css
index 83ae6c24b8..06598d0529 100644
--- a/packages/ui/src/components/Accordion/Accordion.module.css
+++ b/packages/ui/src/components/Accordion/Accordion.module.css
@@ -21,18 +21,12 @@
width: 100%;
border-radius: var(--bui-radius-3);
padding: var(--bui-space-3);
+ }
- &[data-bg='neutral-1'] {
- background-color: var(--bui-bg-neutral-1);
- }
-
- &[data-bg='neutral-2'] {
- background-color: var(--bui-bg-neutral-2);
- }
-
- &[data-bg='neutral-3'] {
- background-color: var(--bui-bg-neutral-3);
- }
+ .bui-Accordion[data-bg='danger'],
+ .bui-Accordion[data-bg='warning'],
+ .bui-Accordion[data-bg='success'] {
+ background-color: transparent;
}
.bui-AccordionTrigger {
diff --git a/packages/ui/src/components/Box/Box.module.css b/packages/ui/src/components/Box/Box.module.css
index dd1ff447bc..688358fda0 100644
--- a/packages/ui/src/components/Box/Box.module.css
+++ b/packages/ui/src/components/Box/Box.module.css
@@ -22,28 +22,4 @@
font-weight: var(--bui-font-weight-regular);
color: var(--bui-fg-primary);
}
-
- .bui-Box[data-bg='neutral-1'] {
- background-color: var(--bui-bg-neutral-1);
- }
-
- .bui-Box[data-bg='neutral-2'] {
- background-color: var(--bui-bg-neutral-2);
- }
-
- .bui-Box[data-bg='neutral-3'] {
- background-color: var(--bui-bg-neutral-3);
- }
-
- .bui-Box[data-bg='danger'] {
- background-color: var(--bui-bg-danger);
- }
-
- .bui-Box[data-bg='warning'] {
- background-color: var(--bui-bg-warning);
- }
-
- .bui-Box[data-bg='success'] {
- background-color: var(--bui-bg-success);
- }
}
diff --git a/packages/ui/src/components/Card/Card.module.css b/packages/ui/src/components/Card/Card.module.css
index 91c533aaa5..617c922707 100644
--- a/packages/ui/src/components/Card/Card.module.css
+++ b/packages/ui/src/components/Card/Card.module.css
@@ -29,18 +29,6 @@
padding: var(--bui-space-3);
}
- .bui-Card[data-bg='neutral-1'] {
- --bui-card-bg: var(--bui-bg-neutral-1);
- }
-
- .bui-Card[data-bg='neutral-2'] {
- --bui-card-bg: var(--bui-bg-neutral-2);
- }
-
- .bui-Card[data-bg='neutral-3'] {
- --bui-card-bg: var(--bui-bg-neutral-3);
- }
-
.bui-Card:has(.bui-CardHeader, .bui-CardBody, .bui-CardFooter) {
padding: 0;
}
@@ -127,8 +115,8 @@
margin-bottom: -1.5rem;
background: linear-gradient(
to bottom,
- var(--bui-card-bg),
- rgb(from var(--bui-card-bg) r g b / 0)
+ var(--bui-bg-inherit),
+ rgb(from var(--bui-bg-inherit) r g b / 0)
);
pointer-events: none;
opacity: 0;
@@ -146,8 +134,8 @@
margin-top: -1.5rem;
background: linear-gradient(
to top,
- var(--bui-card-bg),
- rgb(from var(--bui-card-bg) r g b / 0)
+ var(--bui-bg-inherit),
+ rgb(from var(--bui-bg-inherit) r g b / 0)
);
pointer-events: none;
opacity: 0;
diff --git a/packages/ui/src/components/Flex/Flex.module.css b/packages/ui/src/components/Flex/Flex.module.css
index 499326b9ea..0d44fbd12f 100644
--- a/packages/ui/src/components/Flex/Flex.module.css
+++ b/packages/ui/src/components/Flex/Flex.module.css
@@ -23,28 +23,4 @@
/* This helps when using `truncate` on text inside a flex container */
min-width: 0;
}
-
- .bui-Flex[data-bg='neutral-1'] {
- background-color: var(--bui-bg-neutral-1);
- }
-
- .bui-Flex[data-bg='neutral-2'] {
- background-color: var(--bui-bg-neutral-2);
- }
-
- .bui-Flex[data-bg='neutral-3'] {
- background-color: var(--bui-bg-neutral-3);
- }
-
- .bui-Flex[data-bg='danger'] {
- background-color: var(--bui-bg-danger);
- }
-
- .bui-Flex[data-bg='warning'] {
- background-color: var(--bui-bg-warning);
- }
-
- .bui-Flex[data-bg='success'] {
- background-color: var(--bui-bg-success);
- }
}
diff --git a/packages/ui/src/components/Grid/Grid.module.css b/packages/ui/src/components/Grid/Grid.module.css
index 8fdaf15c3b..ff98e9337f 100644
--- a/packages/ui/src/components/Grid/Grid.module.css
+++ b/packages/ui/src/components/Grid/Grid.module.css
@@ -20,34 +20,4 @@
.bui-Grid {
display: grid;
}
-
- .bui-Grid[data-bg='neutral-1'],
- .bui-GridItem[data-bg='neutral-1'] {
- background-color: var(--bui-bg-neutral-1);
- }
-
- .bui-Grid[data-bg='neutral-2'],
- .bui-GridItem[data-bg='neutral-2'] {
- background-color: var(--bui-bg-neutral-2);
- }
-
- .bui-Grid[data-bg='neutral-3'],
- .bui-GridItem[data-bg='neutral-3'] {
- background-color: var(--bui-bg-neutral-3);
- }
-
- .bui-Grid[data-bg='danger'],
- .bui-GridItem[data-bg='danger'] {
- background-color: var(--bui-bg-danger);
- }
-
- .bui-Grid[data-bg='warning'],
- .bui-GridItem[data-bg='warning'] {
- background-color: var(--bui-bg-warning);
- }
-
- .bui-Grid[data-bg='success'],
- .bui-GridItem[data-bg='success'] {
- background-color: var(--bui-bg-success);
- }
}
diff --git a/packages/ui/src/css/colors.stories.tsx b/packages/ui/src/css/colors.stories.tsx
index 2d1a3614a7..49e3cdaec5 100644
--- a/packages/ui/src/css/colors.stories.tsx
+++ b/packages/ui/src/css/colors.stories.tsx
@@ -23,6 +23,24 @@ const meta = preview.meta({
tags: ['!manifest'],
});
+/**
+ * A `` styled with `background: var(--bui-bg-inherit)` should always
+ * resolve to the same color as the surrounding bg provider — at every level
+ * of the neutral chain and inside intent surfaces.
+ */
+const Probe = ({ label }: { label: string }) => (
+
+ {label}
+
+);
+
export const Default = meta.story({
render: () => (
@@ -151,3 +169,37 @@ export const Default = meta.story({
),
});
+
+export const BgInherit = meta.story({
+ render: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+});
diff --git a/packages/ui/src/css/core.css b/packages/ui/src/css/core.css
index 1047215ee8..74f5960017 100644
--- a/packages/ui/src/css/core.css
+++ b/packages/ui/src/css/core.css
@@ -47,4 +47,38 @@
[data-theme-mode='light'] {
color-scheme: light;
}
+
+ :root {
+ --bui-bg-inherit: var(--bui-bg-app);
+ }
+
+ [data-bg='neutral-1'] {
+ background-color: var(--bui-bg-neutral-1);
+ --bui-bg-inherit: var(--bui-bg-neutral-1);
+ }
+
+ [data-bg='neutral-2'] {
+ background-color: var(--bui-bg-neutral-2);
+ --bui-bg-inherit: var(--bui-bg-neutral-2);
+ }
+
+ [data-bg='neutral-3'] {
+ background-color: var(--bui-bg-neutral-3);
+ --bui-bg-inherit: var(--bui-bg-neutral-3);
+ }
+
+ [data-bg='danger'] {
+ background-color: var(--bui-bg-danger);
+ --bui-bg-inherit: var(--bui-bg-danger);
+ }
+
+ [data-bg='warning'] {
+ background-color: var(--bui-bg-warning);
+ --bui-bg-inherit: var(--bui-bg-warning);
+ }
+
+ [data-bg='success'] {
+ background-color: var(--bui-bg-success);
+ --bui-bg-inherit: var(--bui-bg-success);
+ }
}