Breadcrumbs

Render a Linear-style breadcrumb trail with links, dropdown menus, and Home/Back controls.

Breadcrumbs is a client component that renders a data-driven breadcrumb trail for the Next.js App Router. Pass an ordered items array; each crumb can be a link, a button, plain current-page text or custom content, and can open a dropdown menu. Optional Home and Back buttons and right-aligned actions complete the header row.

Import#

typescript
import { Breadcrumbs, BreadcrumbCrumb, pathToBreadcrumbItems, humanizeSegment } from "@reactberry/system/blocks";
import type { BreadcrumbItem, BreadcrumbsProps } from "@reactberry/system/blocks";

Usage#

typescript
import { Breadcrumbs } from "@reactberry/system/blocks";
import { Button } from "@reactberry/system/elements";

export default function ProjectHeader() {
  return (
    <Breadcrumbs
      showHome
      items={[
        { label: "Projects", href: "/projects" },
        { label: "Website", current: true },
      ]}
      actions={
        <Button as="button" type="button" variant="ghost" $size="small">
          Share
        </Button>
      }
    />
  );
}

Examples#

Sibling menu#

Give a crumb a menu to add a chevron that opens a popover. A function receives close, so the menu can dismiss itself after a selection.

From a pathname#

pathToBreadcrumbItems turns a pathname into crumbs with cumulative hrefs and humanized labels. Use labels to replace ids with names.

Back button, icons and truncation#

showBack adds a Back button that calls onBack (here a counter) instead of router.back(). Crumbs accept an icon, an onClick when there is no href, and a maxWidth for long labels.

Back pressed 0 times

API#

PropTypeDefaultDescription
items*
BreadcrumbItem[]
—

Ordered crumbs, root first.

separator
ReactNode
—

Node rendered between crumbs. Defaults to a right chevron.

showHome
boolean
false

Show a leading Home button linking to homeHref.

homeHref
string
/

Home destination. Default "/".

showBack
boolean
false

Show a leading Back button.

onBack
(() => void)
—

Back handler. Defaults to router.back().

actions
ReactNode
—

Right-aligned actions (e.g. favourite / overflow menu).

dataTest
string
breadcrumbs

Prefix for data-test hooks. Default "breadcrumbs".

Remaining props are spread onto the root Group (rendered as a nav), so layout and style props such as flex, px and minWidth work.

PropTypeDefaultDescription
id
string
—

Stable identity used as the React key. Falls back to href, then label, then the index.

label
string
—

Text label, truncated to one line.

href
string
—

Renders the crumb as a Next.js Link unless it is current.

onClick
() => void
—

Renders the crumb as a button when there is no href and it is not current.

icon
ReactNode
—

Leading visual rendered before the label.

render
ReactNode
—

Custom content that replaces the icon and label. The link, button or current wrapper still applies.

menu
ReactNode | ((props: { close: () => void }) => ReactNode)
—

Popover content opened from a chevron next to the crumb.

current
boolean
—

Marks the current page: no link or button, primary colour and aria-current="page".

maxWidth
string
"12rem"

Maximum width of the icon and label before truncation.

dataTest
string
—

Suffix for the crumb's data-test hook. Defaults to the slugified label.

Renders a single crumb. Breadcrumbs uses it for every item; use it directly to build a custom trail.

PropTypeDefaultDescription
item*
BreadcrumbItem
—

The crumb to render.

dataTest
string
"breadcrumbs"

Prefix for the data-test hook.

pathToBreadcrumbItems#

Builds BreadcrumbItem[] from a pathname. Each segment becomes a crumb whose href is the path up to that segment.

PropTypeDefaultDescription
pathname*
string
—

Pathname such as "/projects/42/settings". Empty segments are ignored.

options.labels
Record<string, string>
{}

Label overrides keyed by the raw segment ("42") or the cumulative href ("/projects/42"). Other segments go through humanizeSegment.

options.exclude
(segment: string, index: number) => boolean
—

Return true to drop a segment, for example a route group or a bare id.

options.markLastCurrent
boolean
true

Marks the last crumb as current. Set to false to keep its link.

Returns BreadcrumbItem[].

humanizeSegment#

humanizeSegment(segment: string): string decodes a URL segment, replaces - and _ with spaces and capitalizes each word: "project-templates" becomes "Project Templates".

Accessibility#

  • The root is a nav with aria-label="Breadcrumb".
  • The current crumb has aria-current="page" and is not interactive.
  • Crumbs with href render a Next.js Link; crumbs with only onClick render a native button type="button".
  • The Home and Back buttons have aria-label="Home" and aria-label="Go back".
  • The default separator icon is aria-hidden.
  • The menu chevron is a Headless UI popover button with no accessible name. Crumbs are not wrapped in a list (ol/li).

Notes#

  • Breadcrumbs calls useRouter from next/navigation, so it must render inside the Next.js App Router.
  • The Home button counts as the root crumb, so a separator follows it. The Back button has no separator.
  • href takes precedence over onClick. A current crumb ignores both.
  • The menu opens with placement="bottom start".
  • data-test hooks are <dataTest>-back, <dataTest>-home, <dataTest>-<crumb> and <dataTest>-<crumb>-menu, where <crumb> is the item's dataTest or slugified label.
  • slugify is exported from the Breadcrumbs module but not from @reactberry/system/blocks.