fix(ui): collapse plugin header spacing before headers

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2026-04-30 09:33:18 +01:00
parent a9f3d7189f
commit 021b36800f
7 changed files with 62 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Added a stable DOM marker to the legacy Header so adjacent layout components can coordinate spacing without relying on generated class names.
+1 -1
View File
@@ -2,6 +2,6 @@
'@backstage/ui': patch
---
Adjusted PluginHeader spacing so headers with and without tabs align more consistently with surrounding page content.
Adjusted PluginHeader spacing and borders so headers with and without tabs align more consistently with surrounding page content, including when paired with page headers.
**Affected components:** PluginHeader, Header
@@ -228,7 +228,11 @@ export function Header(props: PropsWithChildren<Props>) {
return (
<>
<Helmet titleTemplate={titleTemplate} defaultTitle={defaultTitle} />
<header style={style} className={classes.header}>
<header
style={style}
className={classes.header}
data-backstage-core-header=""
>
<Box className={classes.leftItemsBox}>
<TypeFragment
classes={classes}
+1
View File
@@ -60,6 +60,7 @@
},
"devDependencies": {
"@backstage/cli": "workspace:^",
"@backstage/core-components": "workspace:^",
"@storybook/react-vite": "^10.3.3",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "^16.0.0",
@@ -18,18 +18,29 @@
@layer components {
.bui-PluginHeader {
margin-bottom: var(--bui-space-6);
--bui-plugin-header-margin-bottom: var(--bui-space-6);
--bui-plugin-header-toolbar-border-bottom: solid 1px var(--bui-border-1);
--bui-plugin-header-tabs-border-bottom: 1px solid var(--bui-border-1);
margin-bottom: var(--bui-plugin-header-margin-bottom);
padding-inline: var(--bui-space-5);
margin-top: var(--bui-space-4);
}
.bui-PluginHeader:has(+ .bui-HeaderTop),
.bui-PluginHeader:has(+ [data-backstage-core-header]) {
--bui-plugin-header-margin-bottom: 0;
--bui-plugin-header-toolbar-border-bottom: none;
--bui-plugin-header-tabs-border-bottom: none;
}
.bui-PluginHeaderToolbar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
color: var(--bui-fg-primary);
border-bottom: solid 1px var(--bui-border-1);
border-bottom: var(--bui-plugin-header-toolbar-border-bottom);
padding-bottom: var(--bui-space-4);
&[data-has-tabs] {
@@ -79,6 +90,6 @@
}
.bui-PluginHeaderTabsWrapper {
border-bottom: 1px solid var(--bui-border-1);
border-bottom: var(--bui-plugin-header-tabs-border-bottom);
}
}
@@ -15,6 +15,7 @@
*/
import preview from '../../../../.storybook/preview';
import { Header as CoreHeader } from '@backstage/core-components';
import type { StoryFn } from '@storybook/react-vite';
import { MemoryRouter } from 'react-router-dom';
import { BUIProvider } from '../provider';
@@ -137,6 +138,40 @@ export const SimpleHeader = meta.story({
),
});
export const CoreComponentsHeader = meta.story({
decorators: [withLayout],
render: () => (
<>
<PluginHeader icon={<RiCodeSSlashLine />} title="APIs" />
<CoreHeader title="payments-api" />
<PageContent />
</>
),
});
export const CoreComponentsHeaderWithTabs = meta.story({
decorators: [withLayout],
render: () => (
<>
<PluginHeader
icon={<RiCodeSSlashLine />}
title="APIs"
tabs={[
{ id: 'overview', label: 'Overview', href: '/apis' },
{
id: 'definitions',
label: 'Definitions',
href: '/apis/definitions',
},
{ id: 'consumers', label: 'Consumers', href: '/apis/consumers' },
]}
/>
<CoreHeader title="payments-api" />
<PageContent />
</>
),
});
export const WithTabs = meta.story({
decorators: [withLayout],
render: () => (
+1
View File
@@ -7949,6 +7949,7 @@ __metadata:
resolution: "@backstage/ui@workspace:packages/ui"
dependencies:
"@backstage/cli": "workspace:^"
"@backstage/core-components": "workspace:^"
"@backstage/version-bridge": "workspace:^"
"@braintree/sanitize-url": "npm:^7.1.2"
"@internationalized/date": "npm:^3.12.0"