Breadcrumbs

Shows the current page's place in the hierarchy, with a link back to each level.

Installation

  1. Install the package.
npm install @hashintel/ds-components
  1. Import the component.
import { BreadCrumbs } from "@hashintel/ds-components";

export const EntityTrail = () => (
  <BreadCrumbs>
    <BreadCrumbs.Item href="/workspace">Acme</BreadCrumbs.Item>
    <BreadCrumbs.Item href="/workspace/entities">Entities</BreadCrumbs.Item>
    <BreadCrumbs.Item>Quarterly report</BreadCrumbs.Item>
  </BreadCrumbs>
);

When to use

  • Do: Use Breadcrumbs on pages nested three or more levels deep, so users can see where they are and step back up.
  • Do: Use it as secondary navigation under the page header — it supplements the sidebar or main nav, never replaces it.
  • Do: Use it when users land mid-hierarchy from search, notifications, or shared links and need to orient themselves.
  • Do: Use subItems to let users jump across to a level's siblings without going up first.

When not to use

  • Don't: Don't use breadcrumbs for flat, one- or two-level structures — a single back link (Button variant="link") carries the same information with less chrome.
  • Don't: Don't show progress through a multi-step flow — breadcrumbs name places, not steps; use a progress indicator.
  • Don't: Don't reconstruct the user's browsing history — crumbs reflect where a page lives, not how the user got there; the browser's Back button covers history.

Anatomy

<BreadCrumbs>
  <BreadCrumbs.Item href="/workspace">Acme</BreadCrumbs.Item>
  <BreadCrumbs.Item subItems={siblingTypes}>Entity types</BreadCrumbs.Item>
  <BreadCrumbs.Item>Current page</BreadCrumbs.Item>
</BreadCrumbs>

Examples

Basic

Each crumb links to its level with href. The last crumb is the current page — leave it plain (no href, onClick, or subItems) and it renders as text with aria-current="page".

Action crumbs

Use onClick when navigation goes through a router, or when a crumb performs an action — here the current crumb opens a rename prompt. href, onClick, and subItems are mutually exclusive: a crumb is exactly one of link, button, menu, or plain text.

import { BreadCrumbs } from "@hashintel/ds-components";

export const FlowRunTrail = ({
  openFlows,
  openFlow,
  renameRun,
}: {
  openFlows: () => void;
  openFlow: () => void;
  renameRun: () => void;
}) => (
  <BreadCrumbs>
    <BreadCrumbs.Item onClick={openFlows}>Flows</BreadCrumbs.Item>
    <BreadCrumbs.Item onClick={openFlow}>Email triage</BreadCrumbs.Item>
    <BreadCrumbs.Item onClick={renameRun}>Run #42</BreadCrumbs.Item>
  </BreadCrumbs>
);

subItems turns a crumb into a menu of related destinations — typically the siblings of that level. Sub-items can nest, and they keep working when the crumb collapses: it becomes a submenu inside the ellipsis menu.

Sizes

md is the default. Match the trail to the chrome around it — xxs–sm for dense headers and panels, lg for spacious page titles.

With icons

iconName puts an icon before the label. Use icons consistently — every crumb or none — so an icon doesn't read as emphasis.

Tooltips

Set tooltip for extra context on hover, and tooltipOptions to adjust position or delays. Truncated crumbs already get an automatic tooltip with the full label, so reserve tooltips for additional context — see Truncation.

Responsive collapse

When the container gets too narrow, middle crumbs collapse — front to back — into a single ellipsis menu, with no props needed. Drag the handle to watch crumbs move in and out of the menu.

Limiting visible crumbs

maxItems caps how many crumbs stay visible regardless of width — the rest collapse into the ellipsis menu. Use it on deep hierarchies where even a wide trail would bury the ends.

Pinned crumbs

noCollapse keeps a crumb visible in place — it never joins the ellipsis menu, under width pressure or a maxItems cap. The last crumb never collapses, and the first crumb is the last item to collapse so reserve it for when an intermediate crumb (or the root crumb) is critical for navigation.

Collapsed labels

collapsedChildren swaps a crumb's label while it sits in the ellipsis menu — use it where the in-trail label is too terse out of context. Open the ellipsis: "Projects" lists as "All projects".

Truncation

maxWidth caps a crumb's width; longer labels already truncate with an ellipsis and gain a tooltip showing the full text, but you may want to set a max width for user-generated crumb names in order to prioritize truncation on those crumbs over others.

Behavior

  • The current page never collapses; other crumbs collapse into a menu from right to left where necessary to fit the available space. The first crumb stays visible as long as possible; in very tight spaces it joins the menu too. Only when nothing else fits does the current page truncate.
  • A crumb whose label is visually truncated gains a tooltip showing the full label, unless an explicit tooltip is set.

Content

  • Label each crumb with the destination page's exact title — users match the trail against pages they know. Nouns, 1–3 words, sentence case.
  • Don't add punctuation or slashes to labels; the trail renders its own separators.
  • Don't hand-abbreviate long user-generated names such as entity titles — cap them with maxWidth and let the automatic tooltip carry the full name.

Accessibility

Breadcrumbs implements the WAI-ARIA breadcrumb pattern.

What you must do

  • Give each <Breadcrumbs> a unique aria-label when a page renders more than one — duplicate "Breadcrumb" landmarks are indistinguishable to screen-reader users.
  • Set a crumb's aria-label only when its visible children aren't a sufficient name, such as icon-only.

API reference

PropTypeDescription
size
"xxs" |⁠ "xs" |⁠ "sm" |⁠ "md" |⁠ "lg"
default: "md"
maxItems
number
ellipsisLabel
string
default: "Show collapsed"
aria-label
string
default: "Breadcrumb"
PropTypeDescription
iconName
"function" |⁠ "filter" |⁠ "at" |⁠ "circle" |⁠ … 137 more
tooltip
string
tooltipOptions
Omit<BaseTooltipProps & { variant?: "light" |⁠ "dark"; }, "children" |⁠ "content">
aria-label
string
href
string
onClick
(() => void)
subItems
ItemOrGroup<BreadcrumbSubItem>[]
maxWidth
MaxWidth<string |⁠ number>
collapsedChildren
ReactNode
noCollapse
boolean

The shape of a crumb's subItems entries, shown in its dropdown. Each takes children plus at most one of href or onClick.

PropTypeDescription
iconName
"function" |⁠ "filter" |⁠ "at" |⁠ "circle" |⁠ … 137 more
tooltip
string
tooltipOptions
Omit<BaseTooltipProps & { variant?: "light" |⁠ "dark"; }, "children" |⁠ "content">
aria-label
string
href
string
onClick
(() => void)
subItems
ItemOrGroup<BreadcrumbSubItem>[]

Was this page helpful?

On this page