Skip to content
txbrendan/ui

Breadcrumb

beta

A trail of links from the top of the site to the current page, in a labeled nav.

Preview

links

collapsed

slashes

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the component.

    npx shadcn@latest add @txbrendan/breadcrumb

Use it for

  • Showing where a page sits in a deep hierarchy, so people can go up a level in one click.
  • Put it at the top of the page, above the page heading.
  • End with BreadcrumbPage for the current page. It is not a link, and it carries aria-current="page".
  • Put a BreadcrumbSeparator between items, never after the last one.
  • For a long trail, keep the first and last two levels and put a BreadcrumbEllipsis in place of the middle.
  • With a router, pass its link as render: <BreadcrumbLink render={<Link href="/docs" />}>Docs</BreadcrumbLink>.

Avoid it for

  • Flat sites one level deep. The main navigation already says where people are.
  • Showing the steps of a flow, like checkout. Use StepDots or a list of steps instead.
  • Replacing the main navigation. A breadcrumb shows the path to this page only.
  • Two navs named "Breadcrumb" on one page. Pass a different aria-label to each.

Props

  • aria-label

    On Breadcrumb. The landmark's name. Rename it when a page has more than one. Left off when you pass aria-labelledby.

    string · default "Breadcrumb"

  • label

    On BreadcrumbEllipsis. What screen readers hear in place of the dots.

    string · default "More pages"

  • Breadcrumb

    The landmark. A <nav> with aria-label="Breadcrumb". Pass aria-label or aria-labelledby to rename it.

    Omit<ComponentProps<"nav">, "color">

  • BreadcrumbList

    Part. The ordered list. It wraps on narrow screens.

    Omit<ComponentProps<"ol">, "color">

  • BreadcrumbItem

    Part. One level. Holds a BreadcrumbLink, a BreadcrumbPage, or a BreadcrumbEllipsis.

    Omit<ComponentProps<"li">, "color">

  • BreadcrumbLink

    Part. A link to a level above. render swaps the <a> for your own element, like a router link, with the same props and classes.

    Omit<ComponentProps<"a">, "color"> & { render?: ReactElement }

  • BreadcrumbPage

    Part. The current page, as text with aria-current="page".

    Omit<ComponentProps<"span">, "color">

  • BreadcrumbSeparator

    Part. The mark between items, a chevron by default. Pass children to use another mark, like "/".

    Omit<ComponentProps<"li">, "color">

  • BreadcrumbEllipsis

    Part. Three dots for levels left out. label is what screen readers hear. Default "More pages".

    Omit<ComponentProps<"span">, "children" | "color"> & { label?: string }

  • className

    Extra classes on any part. Later classes win, so className='text-base' on BreadcrumbList replaces the text size.

    string

Accessibility

  • Breadcrumb renders a <nav> named "Breadcrumb", so screen readers list it with the page's landmarks.
  • The levels are an <ol>, so screen readers say how many there are and where each one is.
  • Separators are <li role="presentation" aria-hidden="true">. Screen readers skip them, and they are left out of the item count.
  • BreadcrumbPage carries aria-current="page" and is not a link, so the current page is not a tab stop.
  • BreadcrumbEllipsis has visually hidden text, "More pages" by default, so the gap is not silent. Its dots are aria-hidden.
  • The ellipsis is not interactive. If people need the hidden levels, put it inside a button that opens a menu of them.
  • Links use muted-foreground and the current page uses foreground. The theme tests hold both to 4.5:1 on the page and on cards.
  • Links show the shared focus ring, which the theme tests hold to 3:1.

Examples

A trail to the current page

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/">Home</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbLink href="/settings">Settings</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Billing</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

With Next.js links

import Link from "next/link";

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink render={<Link href="/" />}>Home</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Docs</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

A long trail with the middle left out

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/">Home</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbEllipsis />
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbLink href="/team">Team</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Members</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

Slashes between items

<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/docs">Docs</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator>/</BreadcrumbSeparator>
    <BreadcrumbItem>
      <BreadcrumbPage>Install</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>