Browse docs
Browse docs
A header bar. Three slots — start, center, end — and that's it. No menus, no navigation logic, no business rules. Just a flexible container that solves the "logo left, search center, user menu right" pattern without forcing your hand on what goes in each slot.
Renders as <header> (banner landmark) by default. Sticky to the top of its scroll container.
import { TopBar } from '@dashforge/tw';
<TopBar
start={<Brand />}
center={<SearchBox />}
end={<UserMenu />}
/>Minimal — just a brand + actions:
<TopBar
start={<Logo />}
end={
<Stack direction="row" gap={2}>
<Button variant="text">Sign in</Button>
<Button color="primary">Sign up</Button>
</Stack>
}
/>With breadcrumbs in the middle:
<TopBar
start={<Logo />}
center={
<Breadcrumbs items={[
{ label: 'Projects', to: '/projects' },
{ label: 'Q4 launch', to: '/projects/q4' },
{ label: 'Tasks' },
]} />
}
end={<UserMenu />}
/>Dashforge
import { TopBar, Stack, Typography, Button, Breadcrumbs, Box } from '@dashforge/tw';
<TopBar
start={
<Stack direction="row" gap={2} align="center">
<Box variant="solid" color="primary" p={2} rounded="md">
<Typography variant="caption">DF</Typography>
</Box>
<Typography variant="body2">Dashforge</Typography>
</Stack>
}
center={
<Breadcrumbs
items={[
{ id: 'projects', label: 'Projects', href: '/projects' },
{ id: 'q4', label: 'Q4 launch', href: '/projects/q4' },
{ id: 'tasks', label: 'Tasks' },
]}
/>
}
end={
<Stack direction="row" gap={2}>
<Button variant="ghost" size="sm">Sign in</Button>
<Button color="primary" size="sm">Sign up</Button>
</Stack>
}
/><TopBar height="sm" start={<Logo />} end={<Actions />} /> {/* 48px */}
<TopBar height="md" start={<Logo />} end={<Actions />} /> {/* 64px — default */}
<TopBar height="lg" start={<Logo />} end={<Actions />} /> {/* 80px */}<TopBar sticky={false} start={<Logo />} end={<Actions />} />By default, position: sticky; top: 0 keeps the bar fixed when the page scrolls. Disable for pages where the bar should scroll away.
The typical wiring — pass it as the header slot:
<AppShell
header={
<TopBar
start={<Logo />}
center={<GlobalSearch />}
end={<UserMenu />}
/>
}
nav={<LeftNav items={NAV_ITEMS} />}
footer={<Footer />}
>
<YourPage />
</AppShell><div> instead of <header>If you're already inside an outer <header> (e.g. nested layouts), use asDiv to avoid double-banner landmarks:
<header>
{/* outer header chrome */}
<TopBar asDiv start={<SubLogo />} end={<SubActions />} />
</header>If you don't use center, you can pass plain children and it fills the middle:
<TopBar start={<Logo />} end={<UserMenu />}>
<SearchBox /> {/* equivalent to center={<SearchBox />} */}
</TopBar>| Prop | Type | Default | Description |
|---|---|---|---|
start | ReactNode | — | Left slot. |
center | ReactNode | — | Middle slot — grows to fill available space. |
end | ReactNode | — | Right slot. |
children | ReactNode | — | Fallback for center when not provided. |
height | 'sm' | 'md' | 'lg' | 'md' | Bar height (48 / 64 / 80px). |
sticky | boolean | true | Apply position: sticky; top: 0. |
asDiv | boolean | false | Render as <div> instead of <header> (avoid nested banner landmarks). |
slotProps | TopBarSlotProps | — | Per-slot overrides. |
sx | string | — | Utility-class override on root. |
root · start · center · end
<header> by default — adds the banner landmark to your page outline (screen readers announce it as "banner region"). If you don't want the landmark (rare), use asDiv.position: sticky (not fixed) — so it stays inside its parent's scroll context. If your page has a custom scroll container (e.g. <div className="h-screen overflow-y-auto">), TopBar sticks to that container's top, not the viewport's. Usually what you want.center slot has flex: 1. If you put a Breadcrumbs there, it spreads across the full mid-section; if you put a centered SearchBox, wrap it in a flex container with justify-center for the visual centering.sx if your stacking is unusual.