Top bar
The Dashboard shell chrome. A sticky 64px bar with a breadcrumb on the left and utilities on the right: Test mode switch, Theme toggle, Notifications bell, Account menu.
Live preview
<TopBar breadcrumb="Home" />Anatomy
The top bar has two zones separated by justify-between. Left: breadcrumb text (single item, no chevron). Right: a group of utilities separated by vertical dividers, ending with the avatar dropdown.
- 1Breadcrumb
Left-side path. Accepts a string (single-item) or an array of segments to render a CaretRight (light, size-3) chevron chain. The last segment is text-foreground (current section); earlier segments are text-muted-foreground and become clickable buttons if onClick is passed.
- 2Theme toggle
Sun / Moon icon button. Toggles the .dark class on <html>.
- 3Notifications bell
IconButton with BellSimple (light). Opens the notification tray in real Dashboard.
- 4GlobalChip
Environment + scope switcher chip. Opens a dropdown with ENVIRONMENT and ACCOUNTS sections. See the dedicated /organisms/global-chip page for full anatomy.
- 5AccountMenu
Avatar dropdown with profile actions. See the dedicated /organisms/account-menu page for full anatomy.
- 6Test mode switch (optional, default off)
Kit Switch labeled 'Test mode'. Opt-in via showTestMode={true}. When on, the account is operating in sandbox; wire host to actually swap keys.
- 7Dividers
Vertical Separator h-6 between each utility group so the utilities read as distinct clusters.
Breadcrumb
The breadcrumb slot accepts either a plain string (single item) or an array of segments. Segments render as a CaretRight-separated chain, and any segment with an onClick becomes a hoverable button. The last segment is always the current section (non-clickable, text-foreground).
<TopBar breadcrumb="Home" /><TopBar
breadcrumb={[
{ label: "Risk conditions", onClick: () => router.push("/risk-conditions") },
{ label: "Rules", onClick: () => router.push("/risk-conditions/rules") },
{ label: "r-005" },
]}
/>- Single-string form for landing pages (Home, Insights) where there's no parent path.
- Segment array for detail views inside a section (Risk conditions › Rules › r-005).
- Only the last segment gets text-foreground — every previous segment is text-muted-foreground.
- Parent segments should be clickable back to their own list — don't leave the trail dead.
- Never nest a menu or dropdown inside a segment — the breadcrumb is for wayfinding only.
When to use
- As the sticky top of any Dashboard-adjacent prototype (pair with Sidebar).
- Prototypes that need Test mode toggle, notifications, or account menu.
- When the flow spans multiple pages of the same Dashboard shell.
When not to use
- Marketing landings — use a marketing top nav.
- Focused modals or wizards — hide the shell entirely.
- As a page-title header — use PageHeader below the top bar instead.
Usage
- Keep the top bar sticky (sticky top-0 z-20) so it stays anchored while content scrolls.
- Order utilities right-to-left by frequency: avatar last, notifications and theme in the middle, Test mode as the outermost feature.
- Use the kit Switch and Separator inside — never redeclare a bespoke switch.
- Fill the breadcrumb with the current section (matches the sidebar selection).
- Don't add a title or logo inside the top bar — logo lives in the Sidebar.
- Don't nest actions or menus inside the breadcrumb slot.
- Don't stack more than 4 utilities on the right — trim rare ones into the account menu.
- Don't rename Test mode to 'Sandbox' or 'Preview' — the copy is canonical.
Composition
TopBar is sticky (position: sticky). Render it as the first child of your page content, after the Sidebar, so it hovers above scroll.
import { TopBar } from "@/components/organisms/top-bar";
import { Sidebar } from "@/components/organisms/sidebar";
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="min-h-screen">
<div className="fixed inset-y-0 left-0 z-30">
<Sidebar />
</div>
<div className="pl-64">
<TopBar breadcrumb="Home" />
<main>{children}</main>
</div>
</div>
);
}Code
<TopBar
breadcrumb="Payments"
accountMenu={{ userName: "Julián Núñez", userEmail: "julian@y.uno" }}
globalChip={{
accounts: [
{ key: "tiendamia-br", label: "Tiendamia BR", type: "organization" },
{ key: "tiendamia-ar", label: "Tiendamia AR", type: "organization" },
],
onAccountChange: (key) => router.push(`/accounts/${key}`),
}}
/><TopBar
breadcrumb="Rules"
showTestMode
globalChip={{
activeEnvironment: "sandbox",
activeAccount: "test-account",
accounts: [
{ key: "test-account", label: "Test account", type: "account" },
],
}}
/>