Gesso
Navigation

Breadcrumb

The path to the current page through its parents, as links ending in the page itself.

Breadcrumb shows where the current page sits inside a hierarchy, as a trail of links that ends in the page itself. It is unstyled structure over <nav>, <ol>, and <li>, with muted ink for the parents and full ink for the current page, and a Phosphor CaretRight between crumbs. Pass the tree into Page header's breadcrumb slot, which takes the place of the back button when both are given.

Command palette

Usage

import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator,
} from '@/components/ui/breadcrumb';

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/issues">Issues</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>GES-184</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

Every crumb but the last is a BreadcrumbLink, and the last is a BreadcrumbPage, which is plain text and not a link. The list wraps onto a second line when the trail is too long for its container.

BreadcrumbLink renders an <a>. With asChild it hands its styling to its one child, so a router link stays a router link.

import Link from 'next/link';

<BreadcrumbLink asChild>
  <Link href="/issues">Issues</Link>
</BreadcrumbLink>

Separators and long trails

BreadcrumbSeparator draws a caret by default, and its children replace it, so <BreadcrumbSeparator>/</BreadcrumbSeparator> gives slashes. An icon inside it is sized to 14px.

BreadcrumbEllipsis is a 36px ... mark for a trail you have shortened, standing in for the crumbs you left out. On its own it is only a mark. Give it onClick and it is a button named by label, "More" unless you set it, or give it asChild and a button of your own, such as a Dropdown menu trigger with its own name, and the dots go inside that button.

Accessibility

  • Breadcrumb is a <nav> landmark labelled "breadcrumb", and the label can be replaced by passing aria-label, for example to translate it. The crumbs are an ordered list, so a screen reader announces the count and each crumb's position.
  • BreadcrumbPage carries aria-current="page", which is how assistive tech finds the current page. It is a <span> and not a link, so it takes no focus.
  • Separators are list items marked role="presentation" and aria-hidden, so the carets are not read out.
  • Links are native anchors in the tab order, with a 2px focus ring on keyboard focus. The hover color change does not animate under reduced motion.
  • A plain BreadcrumbEllipsis is aria-hidden. With onClick it is a named button, and with asChild it is your own control, both with a focus ring, so hidden crumbs can be reached.
  • On a touch screen each link's hit area grows to 44px tall without growing sideways into the next crumb.

When to use something else

  • Sidebar for the app's top-level destinations, which stay on screen. A breadcrumb shows the path to one page, and it does not switch between sections.
  • Tabs for views that share a page and swap panels, and Tab switcher for a short in-page mode switch.
  • A back button on Page header (onBack) when there is one parent and no deeper trail to show.

Install

shadcn add @gesso/breadcrumb

On this page