Breadcrumb
A breadcrumbs is a list of links that help visualize the location of a page within the hierarchical structure of a site, it allows navigation up to any of the ancestors.
Variations
Installation
import { Breadcrumb } from '@harnessio/ui/components'
//...
return ( <Breadcrumb.Root> <Breadcrumb.List> <Breadcrumb.Item> <Breadcrumb.Link href="#">Lorem</Breadcrumb.Link> </Breadcrumb.Item> <Breadcrumb.Separator /> <Breadcrumb.Ellipsis /> <Breadcrumb.Separator /> <Breadcrumb.Item> <Breadcrumb.Link href="#">Ipsum</Breadcrumb.Link> </Breadcrumb.Item> <Breadcrumb.Separator /> <Breadcrumb.Page>Dolor</Breadcrumb.Page> </Breadcrumb.List> </Breadcrumb.Root>)Components
Item
The Item component displays its contents as a node within the breadcrumb.
Link
The Link component can be passed as a child to an Item component to display a clickable breadcrumb item.
Page
The Page component displays the current page (non-clickable, bold text).
Ellipsis
The Ellipsis component displays a truncation indicator. Click to show a dropdown with hidden items.
Copy
The Copy component displays a copy button to copy the breadcrumb path.
RootInteractive
The RootInteractive component displays an interactive root element with an avatar and dropdown chevron. Useful for header navigation.
Anatomy
All parts of the Breadcrumb can be imported and composed as required.
<Breadcrumb.Root> <Breadcrumb.List> <Breadcrumb.Item> <Breadcrumb.RootInteractive /> {/* Interactive root with avatar */} </Breadcrumb.Item> <Breadcrumb.Separator /> <Breadcrumb.Item> <Breadcrumb.Link /> {/* Clickable link */} </Breadcrumb.Item> <Breadcrumb.Separator /> <Breadcrumb.Ellipsis /> {/* Truncation indicator with dropdown */} <Breadcrumb.Separator /> <Breadcrumb.Page /> {/* Current page (non-clickable) */} </Breadcrumb.List> <Breadcrumb.Copy /> {/* Copy path button (outside List) */}</Breadcrumb.Root>- Root — a
<nav aria-label="breadcrumb">landmark that wraps the trail.size(smorxs) scales the whole breadcrumb. - List — an ordered list (
<ol>) holding the steps in order. - Item — a list item (
<li>); it can carry aprefixIconand holds aLink,RootInteractive, or plain content. - Link — a clickable
<a>for an ancestor; supports aprefixIcon. - Separator — the divider between steps (a
/by default); it’s decorative and hidden from assistive tech. - Ellipsis — a truncation control that collapses middle steps into a dropdown of hidden
items. - Page — the current location; non-clickable and marked as the current step.
- Copy — an optional copy-path button, placed inside
Rootbut outsideList. - RootInteractive — a button-styled root with an avatar and a chevron, for header-style navigation.
Best practices
Do
- Use a breadcrumb to show where the current page sits in the hierarchy and to let people jump back up to any ancestor.
- Keep the last step as the current page (
Breadcrumb.Page) and every step before it as aBreadcrumb.Link. - Collapse long trails with
Breadcrumb.Ellipsisrather than letting the row wrap or overflow — keep the first and last steps visible. - Match the
sizeto the surface:smfor standard bars,xsfor dense headers.
Don’t
- Don’t use a breadcrumb as the primary navigation for a flat site with no real hierarchy.
- Don’t make the current page a link — it’s where the user already is.
- Don’t rely on the separator or a
prefixIconto carry meaning; the step’s text label is what matters.
Content
- Label each step with the destination’s real name — the page or section title — in sentence case.
- Keep labels short so the trail stays on one line; truncate the middle with an ellipsis before you shorten meaningful names.
- Use
prefixIconsparingly and only when the icon reinforces the label (a folder, a repo), not as decoration.
Accessibility
Breadcrumb ships proper landmark and list semantics: Root is a <nav aria-label="breadcrumb">, List is an ordered list, and each Item is a list item — so assistive tech announces it as breadcrumb navigation with a numbered trail.
Keyboard
- Each
Linkis a native<a>and a tab stop, activated with Enter. - The
Ellipsisis a button that opens a dropdown; open it with Enter/Space, then move through the hidden items with the arrow keys. CopyandRootInteractiveare native<button>s — tab stops activated with Enter/Space.- The current
Pageis not focusable, since there’s nowhere to navigate.
Labeling
- The current page is marked
aria-current="page", so screen readers announce it as the current location. - Separators are
role="presentation"andaria-hidden, so the/isn’t read out between steps. prefixIcons are decorative — the item’s text label carries the meaning.
Focus & states
- Links and buttons show the standard keyboard focus ring (
:focus-visible) via the--cn-focustoken. - The current
Pagerenders as anaria-disabledlink, so it’s skipped in the tab order.
Known limitations
- The
Ellipsisbutton has no accessible name. It’s an icon-only ghost button rendered withignoreIconOnlyTooltipand just a ”…” icon, so screen readers announce an unlabeled button. Pass anaria-label(e.g. “Show hidden breadcrumbs”) — it forwards to the underlying button. - The current page is a disabled link, not plain text.
Pagerendersrole="link"witharia-disabled="true"; it’s announced as a link you can’t follow. That’s intentional, but don’t place interactive content inside it. RootInteractiveshows a chevron but doesn’t provide the menu. It’s a styled<button>with an avatar and an up/down chevron that implies a dropdown; wiring the actual menu (and the matchingaria-haspopup/aria-expanded) is up to you. Its avatar icon is decorative, so give the button clear text.
Properties
Prop | Required | Default | Type |
|---|---|---|---|
| Root.size | false | 'sm' | 'sm' | 'xs' |
| Item.prefixIcon | false | IconV2NamesType | |
| Link.href | false | string | |
| Link.prefixIcon | false | IconV2NamesType | |
| Link.asChild | false | false | boolean |
| Page.prefixIcon | false | IconV2NamesType | |
| Separator.children | false | / | ReactNode |
| Ellipsis.items | true | BreadcrumbEllipsisItem[] | |
| Ellipsis.onItemSelect | false | (item: BreadcrumbEllipsisItem) => void | |
| Copy.name | true | string | |
| RootInteractive.size | false | 'sm' | 'sm' | 'xs' |
| RootInteractive.isRootOnly | false | false | boolean |
| RootInteractive.avatar | false | Omit<AvatarProps, 'size' | 'rounded'> |