Lumen Docs

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 ReactNode
  • subtitle — optional, renders below title in muted text
  • breadcrumb — 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

  1. Height is h-[52px]. Not py-4. Not h-12. Not h-14. Exactly 52px.
  2. Title text size is text-sm font-semibold. Not text-base, not text-lg. The 52px bar is tight.
  3. Subtitle (if used) is text-[11px] text-text-muted truncate. Stacked under title at smaller size.
  4. 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