Pro

Breadcrumbs

Trail of links to the current page. A long middle folds into a … that opens in place, long labels fade instead of wrapping, and any router’s link fits.

Long trail, folded

Press … to open the middle in place.

Long labels fade

A level with no page

Installation

With UI Polish connected, ask your agent:

Add the UI Polish breadcrumbs to this project.

Or with the shadcn CLI:

npx shadcn@latest add https://uipolish.com/r/breadcrumbs.json
Brings inIcons, Text

Shows where the current page sits, as a trail of links from the top level down to it. The last crumb is the page you're on: in the text color and not a link. A long trail folds its middle into a "…" button that opens it in place, and a long label fades out at its end instead of wrapping or pushing the rest off the line. Links render through your router's link component.

TSX
<Breadcrumbs  as={Link}  items={[    { label: "Events", href: "/events" },    { label: "Saturday supper", href: "/events/1182" },    { label: "Guests" },  ]}/>

When to use it

  • Pages deep in a hierarchy that people reach from search or a shared link: a guest in an event in a season. The trail says where they are and gets them up a level.
  • Above the page title, as the first thing in the page's header.

When not to

  • Flat apps, where every page is one level down: the sidebar or tabs already say where you are.
  • The steps of a flow (cart, shipping, payment): those are steps, not places, and need a progress indicator.
  • Browser history. A breadcrumb shows the hierarchy, not the path you took to get here; that's the back button.

Props

Every <nav> prop passes through.

PropWhat it does
itemsThe trail, top level first: { label, href? }. The last item is the current page and is never a link. An item without href is a level with no page of its own and shows as plain text
asYour router's link component (Link from Next). Defaults to <a>. Gets href, className and the label
maxTrails longer than this fold to the first crumb, "…" and the last max − 2. At least 3; defaults to 4
aria-labelNames the nav. Defaults to "Breadcrumb"

Set --breadcrumbs-label-max on the nav to change where a long label starts to fade (20em by default).

States

StateWhat you seeHow
LinkMuted text<a>
HoverA fill behind the crumb, text in the text color@media (hover: hover)
PressDarker fill in 80ms:active
FocusA line just inside the crumb's pill, instantly:focus-visible
Current pageText color, a step heavier, no hover or pressaria-current="page"
Level with no pageMuted text, no hover or pressno href
FoldedFirst crumb, "…", the last twomore than max items
Long labelIts last 24px fade, only when cut; pointing at it shows the full label in a native tooltiptruncate from text

Layout

Text is the Small step (13px), each crumb a 24px pill with 6px of padding, and a 14px chevron between crumbs in the subtle color. The pills reach past the start edge by their padding, so the first label's text lines up with the title under it and the hover fill hangs outside.

A trail too long for its line wraps between crumbs, never inside one, and each crumb keeps its chevron with it. A label fades from 20em, or sooner when it alone is wider than its line. On touch screens every link and the fold get a 40px hit area, and wrapped lines open to 16px apart so targets don't overlap.

Motion

WhatDurationEasing
Crumbs after the fold slide to their new places as it opens--ui-dur-move--ui-ease-move
Crumbs that open fade in where the "…" was--ui-dur-fast--ui-ease-enter
Hover and press fills, text color--ui-dur-instant--ui-ease-color

Opening the fold is the only movement. The crumbs already on screen slide (FLIP on translate, onto the next line if the trail now wraps) rather than jumping to make room. Nothing animates on the first paint. Under prefers-reduced-motion: reduce the crumbs land at once.

Accessibility

  • <nav aria-label="Breadcrumb"> around an ordered list, so screen readers announce a landmark and "list, 3 items".
  • The current page is aria-current="page" and not a link: a link to the page you're on goes nowhere.
  • Chevrons are drawn, aria-hidden, so the trail is read as names, not "greater than". They turn under right-to-left.
  • The fold is a real button, named for what it does ("Show 3 more levels"). Opening it moves focus to the first link it revealed, since the button itself is gone.
  • A faded label is still all in the DOM, so screen readers read it whole.

Before / after

Before: slashes as text, read aloud between every crumb; the current page is a link to itself; and a long event name wraps the trail onto three lines.

TSX
<div className="crumbs">  <a href="/events">Events</a> / <a href="/events/1182">{event.name}</a> /{" "}  <a href="/events/1182/guests">Guests</a></div>

After:

TSX
<Breadcrumbs  as={Link}  items={[    { label: "Events", href: "/events" },    { label: event.name, href: `/events/${event.id}` },    { label: "Guests" },  ]}/>