Skip to content
cennge-ui
GitHubv0.3.1, changelog

Breadcrumbs

The trail from the top of a hierarchy down to the current page, every level above it one click away.

144 lines · TypeScript

  1. The last item is the page you are on: plain text, marked as the current page for screen readers.
  2. In the file header, click … to bring back the folders it hides.
  3. Out of room on its line, the full trail below wraps between items.
Live: click it, use the keys.
Import
import { Breadcrumbs, BreadcrumbItem } from "cennge-ui";
Size
1.1 KB gzip for this import, its dependencies aside
Pattern
WAI-ARIA breadcrumb: a named <nav> around an ordered list, aria-current="page" on the last item
Keyboard
Tab Enter
State
None to hold: the collapsed middle opens on a click and stays open
SSR
Rendered on the server in the Next.js check; hydrates without a warning
Separators
Hidden from screen readers; a chevron unless you pass your own
Tests
Unit tests

When to use#

Breadcrumbs show where a page sits in a hierarchy, a file in a repository or a page in a documentation site, and make each level above it one click away. They sit at the top of the page, under the main navigation, and they do not replace it: they only lead upwards.

Similar#

  • Pagination moves along a sequence of pages at the same level; Breadcrumbs move up the hierarchy.
  • Stepper shows how far a task has gone and what is left; Breadcrumbs show where the reader is, not what comes next.

Collapse a long trail#

With maxItems, a longer trail shows only that many items: itemsBeforeCollapse from the start (one unless you say otherwise), the rest from the end, and a … button between them. A click on it shows the whole trail.

collapse.tsx
import { BreadcrumbItem, Breadcrumbs } from "cennge-ui";

const tree = "https://github.com/Cennge/cennge-ui/tree/main";

export default function CollapsedTrail() {
  return (
    <Breadcrumbs maxItems={4} itemsBeforeCollapse={2} aria-label="Source file">
      <BreadcrumbItem href="https://github.com/Cennge">Cennge</BreadcrumbItem>
      <BreadcrumbItem href="https://github.com/Cennge/cennge-ui">cennge-ui</BreadcrumbItem>
      <BreadcrumbItem href={`${tree}/src`}>src</BreadcrumbItem>
      <BreadcrumbItem href={`${tree}/src/components`}>components</BreadcrumbItem>
      <BreadcrumbItem href={`${tree}/src/components/navigation-menu`}>navigation-menu</BreadcrumbItem>
      <BreadcrumbItem>navigation-menu.tsx</BreadcrumbItem>
    </Breadcrumbs>
  );
}

With asChild a BreadcrumbItem gives its look to your own link, here Next.js Link. startContent is not drawn in that case: put an icon inside the link, as the home icon here.

next-links.tsx
import Link from "next/link";
import { BreadcrumbItem, Breadcrumbs } from "cennge-ui";

function HomeIcon() {
  return (
    <svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
      <path d="M4 10.5 12 4l8 6.5V20h-5.5v-5.5h-5V20H4v-9.5Z" strokeLinejoin="round" />
    </svg>
  );
}

export default function DocsTrail() {
  return (
    <Breadcrumbs>
      <BreadcrumbItem asChild>
        <Link href="/">
          <HomeIcon />
          cennge-ui
        </Link>
      </BreadcrumbItem>
      <BreadcrumbItem asChild>
        <Link href="/docs/">Docs</Link>
      </BreadcrumbItem>
      <BreadcrumbItem>Breadcrumbs</BreadcrumbItem>
    </Breadcrumbs>
  );
}

Separators and sizes#

separator takes any node, a slash here, in place of the chevron. size sets the text: sm, md or lg.

separators.tsx
import { BreadcrumbItem, Breadcrumbs } from "cennge-ui";

export default function TrailSizes() {
  return (
    <div className="flex flex-col gap-4">
      <Breadcrumbs size="sm" separator="/" aria-label="Breadcrumb, small">
        <BreadcrumbItem href="https://github.com/Cennge">Cennge</BreadcrumbItem>
        <BreadcrumbItem href="https://github.com/Cennge/ai-niche-scout">ai-niche-scout</BreadcrumbItem>
        <BreadcrumbItem>Settings</BreadcrumbItem>
      </Breadcrumbs>
      <Breadcrumbs size="lg" aria-label="Breadcrumb, large">
        <BreadcrumbItem href="https://github.com/Cennge">Cennge</BreadcrumbItem>
        <BreadcrumbItem href="https://github.com/Cennge/spredo-crypto-screener">spredo-crypto-screener</BreadcrumbItem>
        <BreadcrumbItem>Releases</BreadcrumbItem>
      </Breadcrumbs>
    </div>
  );
}

Accessibility#

The trail is a <nav> named "Breadcrumb", and the items are an ordered list, so screen readers say how many levels there are. Rename it with aria-label when a page has more than one trail or speaks another language. The last item becomes the current page unless you set its isCurrent yourself; isCurrent={false} keeps it a link. The … button is named "Show all breadcrumbs".

Props#

PropTypeDefault
separator
React.ReactNodeBetween items.
a chevron
maxItems
numberCollapse the middle into "…" when there are more items than this.
–
itemsBeforeCollapse
numberItems kept before the "…".
1
size
"sm""md""lg"
"md"
aria-label
stringDefines a string value that labels the current element.
"Breadcrumb"
PropTypeDefault
href
stringThe page this item points to. Without it the item renders as text.
–
isCurrent
booleanThe current page. Set automatically on the last item.
–
asChild
booleanRender your router's link (e.g. Next.js <Link>) with breadcrumb styles.
–
startContent
React.ReactNode
–

Also takes every attribute of <a>.