Skip to content

ComponentsNavigation

Breadcrumbs

Show where the current page sits in a hierarchy, with a link back to each level. Chevron, slash or dot separators, two sizes, icons, dynamic items and onAction for in-app navigation. The last item is marked as the current page automatically.

React AriaSource

Installation

pnpm dlx shadcn@latest add @desyne/breadcrumbs

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import { Breadcrumb, Breadcrumbs } from "@/components/ui/breadcrumbs";
tsx
<Breadcrumbs>
  <Breadcrumb href="/">Home</Breadcrumb>
  <Breadcrumb href="/projects">Projects</Breadcrumb>
  <Breadcrumb>Settings</Breadcrumb>
</Breadcrumbs>

The last Breadcrumb is the current page. It gets aria-current="page", is rendered as non-interactive text even if it has an href, and has no separator after it.

When to use

  • Breadcrumbs — secondary navigation that shows the path to the current page in a hierarchy two or more levels deep: file systems, product catalogs, settings, docs.
  • Tabs — sibling views at the same level, not a path.
  • Link — a single "Back to…" link is often enough for shallow hierarchies and small screens.
  • Sidebar — primary navigation. Breadcrumbs complement it; they don't replace it.

Anatomy

tsx
<Breadcrumbs>                 {/* <ol> */}
  <Breadcrumb href="…" icon>  {/* <li> › link + separator */}
    Label
  </Breadcrumb>
  <Breadcrumb>                {/* current page: no link, no separator */}
    Label
  </Breadcrumb>
</Breadcrumbs>
PartRendersNotes
Breadcrumbs<ol>Labelled "Breadcrumbs" by default (localized). Sets the separator style and text size for its items. Wraps onto multiple lines when needed.
Breadcrumb<li>One level. Contains a React Aria Link with the optional icon and the label, or the children as-is with link={false}.
Link<a>, or <span role="link">An <a> when href is set; a <span> for the current item, disabled items and items without href.
Separator<svg> or <span>Chevron, slash or dot after every item except the current one. aria-hidden.

Examples

Separators

chevron (default) suits app UIs, slash suits repository and workspace paths, and dot is a quieter option for marketing pages and metadata.

  1. Docs
  2. Components
  3. Breadcrumbs
  1. Docs
  2. Components
  3. Breadcrumbs
  1. Docs
  2. Components
  3. Breadcrumbs

Sizes

md (14px, default) above page titles, sm (12px) in dense headers, toolbars and cards.

  1. Store
  2. Audio
  3. Headphones
  4. Studio Pro Wireless
  1. Store
  2. Audio
  3. Headphones
  4. Studio Pro Wireless

With icons

Pass icon to show an icon before the label. Icons inside the link are sized to 14px.

  1. Home
  2. Documents
  3. Q3 report.pdf

Icon-only home

Keep the first level compact with an icon, and put the label in an sr-only span so the link still has an accessible name.

  1. Home
  2. Help Center
  3. Billing
  4. Update a payment method

Long labels

Wrap a label in a <span> with max-w-* and truncate to cap its width, and repeat the full text in title so it's available on hover. The full text stays in the accessibility tree.

  1. Engineering
  2. Platform Infrastructure and Developer Experience
  3. Quarterly planning
  4. Q3 2026 roadmap: service mesh migration and cost review

Dynamic items

Pass items and a render function instead of static children. Each item needs a unique id.

Handling actions

Without href, items render as link-role <span>s and pressing one calls onAction on Breadcrumbs with the item's id. Use this for in-app navigation that isn't URL based, like a folder picker.

  1. Drive
  2. Design
  3. Brand
  • guidelines.pdf

Disabled

isDisabled on Breadcrumbs makes every item non-interactive. The links are dimmed to 50% opacity with a not-allowed cursor; the current item keeps its normal style.

  1. Home
  2. Projects
  3. Settings

With a router

Breadcrumb links are React Aria Links, so they go through your router when the app is wrapped in React Aria's RouterProvider. With the Next.js App Router:

app/providers.tsxtsx
"use client";

import { useRouter } from "next/navigation";
import { RouterProvider } from "react-aria-components";

export function Providers({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  return <RouterProvider navigate={router.push}>{children}</RouterProvider>;
}
tsx
<Breadcrumbs>
  <Breadcrumb href="/settings">Settings</Breadcrumb>
  <Breadcrumb href="/settings/team">Team</Breadcrumb>
  <Breadcrumb>Roles</Breadcrumb>
</Breadcrumbs>

Recipes

Small breadcrumbs above the page title, with a status Badge and actions on the right.

  1. Products
  2. Headphones
  3. Studio Pro Wireless

Studio Pro Wireless

Active

SKU HP-2041 · 318 in stock · Updated 2 hours ago

Collapsed path

For deep hierarchies, keep the first and last levels and move the middle ones into a Menu. The collapsed level is a Breadcrumb with link={false}, which renders its children (here a menu trigger) as-is instead of wrapping them in a link, and still gets a separator.

  1. Wiki
  2. Incidents
  3. Database failover

App header

A workspace path in an app's top bar: an Avatar as the first icon, a plan badge inside a crumb, and a slash separator. The breadcrumbs are wrapped in a <nav> landmark.

Accessibility

  • Renders an ordered list (<ol>) labelled "Breadcrumbs" by default. Pass aria-label to change it, and wrap the list in a <nav> element when it's the page's breadcrumb trail so it's exposed as a navigation landmark.
  • The last item has aria-current="page" and isn't focusable or interactive.
  • Separators are aria-hidden, so screen readers announce only the labels.
  • Items with an href are native links: middle-click, "open in new tab" and the browser's link preview work.
  • Give icon-only items a text label with sr-only. aria-label on Breadcrumb is applied to the <li>, not the link.

Keyboard

KeyAction
Tab / Shift+TabMoves between breadcrumb links (the current item is skipped)
EnterFollows the focused link, or calls onAction

Styling

Data attributes

On each Breadcrumb (<li>) and its link:

AttributePresent when
data-currentIt's the last item (the current page)
data-disabledIt's the current item, or isDisabled is set on Breadcrumbs

On the link only:

AttributePresent when
data-hovered / data-pressedHovered / being pressed
data-focused / data-focus-visibleFocused / focused with the keyboard

The current item's link is font-medium text-foreground; the others are text-muted-foreground and turn text-foreground on hover. Disabled links (other than the current item) get opacity-50 and cursor-not-allowed.

Slots

data-slotElement
breadcrumbs<ol> root
breadcrumbEach <li>

Customizing

  • className on Breadcrumbs styles the list (a wrapping flex row with gap-1.5). It must be a string.
  • className on Breadcrumb styles the <li>, and accepts a function of { isCurrent, isDisabled }.
  • To restyle the links, target them from the list, e.g. className="[&_a]:underline".
  • With link={false}, the children aren't wrapped or styled, and isDisabled on Breadcrumbs doesn't reach them. Disable a menu trigger inside yourself.

API Reference

Prop

Type

Also accepts every prop of React Aria's Breadcrumbs.

Prop

Type

  • Link — the link used inside each breadcrumb.
  • Sidebar — primary navigation, often paired with breadcrumbs in the content header.
  • Menu — for collapsed levels in deep paths.
  • Tabs — switching between sibling views.