Topbar
Page header. Every top bar in Lumen uses this primitive. Located at apps/web/components/layout/topbar.tsx.
Usage
<Topbar
title="Marketing"
breadcrumb={[
{ label: "Home", href: "/" },
{ label: "Projects", href: "/projects" },
{ label: "Marketing", icon: <ProjectDot color="#e0a020" /> },
]}
right={
<>
<Button variant="icon-only" size="sm"><SettingsIcon /></Button>
<Button variant="icon-only" size="sm"><IconShare /></Button>
</>
}
/>
Structure
Top row — exactly h-[52px]:
┌──────────────────────────────────────────────────────────┐
│ Title (semibold, sm) [right slot] │
└──────────────────────────────────────────────────────────┘
h-[52px] · px-6 · flex · items-center · border-b
Below — breadcrumb row (optional):
┌──────────────────────────────────────────────────────────┐
│ Home › Projects › Marketing │
└──────────────────────────────────────────────────────────┘
h-8 · bg-surface-2 · px-6 · border-b
Props
title— string or ReactNodesubtitle— optional, renders below title in muted textbreadcrumb— optional array of{ label, href?, icon? }right— optional ReactNode for action buttons
Breadcrumb items
Each item can have:
label(required)href(optional — makes it a link)icon(optional — left of label, e.g. project color dot)
Last item has no separator after it. Separator is › (U+203A).
Rules
- Height is
h-[52px]. Notpy-4. Noth-12. Noth-14. Exactly 52px. - Title text size is
text-sm font-semibold. Nottext-base, nottext-lg. The 52px bar is tight. - Subtitle (if used) is
text-[11px] text-text-muted truncate. Stacked under title at smaller size. - Right slot is for icon-only sm buttons. Not big primary CTAs (those go inside content).
Examples
Admin page
<Topbar
title="Users"
subtitle="2 of 2 users"
breadcrumb={[
{ label: "Admin", href: "/admin" },
{ label: "Users" },
]}
right={
<Button variant="primary" size="sm" onClick={() => setAddOpen(true)}>
<IconPlus /> Add user
</Button>
}
/>
Project detail
<Topbar
title={project.name}
breadcrumb={[
{ label: "Home", href: "/" },
{ label: "Projects", href: "/projects" },
{
label: project.name,
icon: <span className="w-1.5 h-1.5 rounded-full" style={{ backgroundColor: project.color }} />,
},
]}
right={
<>
<Button variant="icon-only" size="sm" onClick={openSettings}><SettingsIcon /></Button>
<Button variant="icon-only" size="sm" onClick={openShare}><IconShare /></Button>
</>
}
/>
Loading state
<Topbar
title="Loading…"
breadcrumb={[
{ label: "Home", href: "/" },
{ label: "Projects", href: "/projects" },
{ label: "Loading…" },
]}
/>
Don't
- Don't render a Topbar inside another Topbar (caused the "double topbar" bug on /new page)
- Don't pass a button-heavy ReactNode in
right— limit to 2-3 icon buttons or one primary button - Don't use
<h1>manually — the Topbar handles the heading semantically