feat(ui): add --bui-bg-inherit CSS variable (#34124)

* feat(ui): add --bui-bg-inherit CSS variable in core.css

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* refactor(ui): remove duplicated data-bg painting from Box.module.css

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* refactor(ui): remove duplicated data-bg painting from Flex.module.css

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* refactor(ui): remove duplicated data-bg painting from Grid.module.css

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* refactor(ui): centralize Accordion data-bg painting, preserve no-intent behavior

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* refactor(ui): use --bui-bg-inherit for Card scroll-shadow gradients

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* docs(ui): document --bui-bg-inherit token

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* chore: changeset for --bui-bg-inherit

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* docs(ui): add Storybook story for --bui-bg-inherit

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* docs(ui): fold --bui-bg-inherit story into colors stories

Signed-off-by: Johan Persson <johanopersson@gmail.com>

* changeset: Reword for clarity.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Johan Persson <johanopersson@gmail.com>

---------

Signed-off-by: Johan Persson <johanopersson@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Johan Persson
2026-05-05 16:00:47 +02:00
committed by GitHub
parent c8813abee0
commit 37535b2a60
9 changed files with 155 additions and 105 deletions
+24
View File
@@ -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.
+36
View File
@@ -264,6 +264,42 @@ pressed, and disabled variants for interactive states.
</Table.Body>
</Table.Root>
## 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.
<CodeBlock
code={`.searchBarContainer {
position: sticky;
top: 0;
background-color: var(--bui-bg-inherit);
}`}
/>
<Table.Root>
<Table.Header>
<Table.HeaderRow>
<Table.HeaderCell>Prop</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
</Table.HeaderRow>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
<Chip head>--bui-bg-inherit</Chip>
</Table.Cell>
<Table.Cell>
Resolves to the bg color of the nearest enclosing `data-bg` ancestor,
falling back to `--bui-bg-app`.
</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Root>
## Solid background colors
<Table.Root>
@@ -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 {
@@ -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);
}
}
@@ -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;
@@ -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);
}
}
@@ -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);
}
}
+52
View File
@@ -23,6 +23,24 @@ const meta = preview.meta({
tags: ['!manifest'],
});
/**
* A `<div>` 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 }) => (
<div
style={{
backgroundColor: 'var(--bui-bg-inherit)',
padding: '0.5rem 0.75rem',
borderRadius: '0.25rem',
outline: '1px dashed var(--bui-fg-secondary)',
}}
>
<Text>{label}</Text>
</div>
);
export const Default = meta.story({
render: () => (
<div style={{ backgroundColor: 'var(--bui-bg-app)' }}>
@@ -151,3 +169,37 @@ export const Default = meta.story({
</div>
),
});
export const BgInherit = meta.story({
render: () => (
<Flex direction="column" gap="4">
<Probe label="App level (no provider) — resolves to --bui-bg-app" />
<Box bg="neutral" p="4">
<Flex direction="column" gap="3">
<Probe label="Inside neutral-1 — resolves to --bui-bg-neutral-1" />
<Box bg="neutral" p="4">
<Flex direction="column" gap="3">
<Probe label="Inside neutral-2 — resolves to --bui-bg-neutral-2" />
<Box bg="neutral" p="4">
<Probe label="Inside neutral-3 — resolves to --bui-bg-neutral-3" />
</Box>
</Flex>
</Box>
</Flex>
</Box>
<Box bg="danger" p="4">
<Probe label="Inside danger — resolves to --bui-bg-danger" />
</Box>
<Box bg="warning" p="4">
<Probe label="Inside warning — resolves to --bui-bg-warning" />
</Box>
<Box bg="success" p="4">
<Probe label="Inside success — resolves to --bui-bg-success" />
</Box>
</Flex>
),
});
+34
View File
@@ -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);
}
}