Breadcrumbs
Shows the current page's place in the hierarchy, with a link back to each level.
Installation
- Install the package.
npm install @hashintel/ds-components- 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
subItemsto 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>
);Dropdown crumbs
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
tooltipis 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
maxWidthand let the automatic tooltip carry the full name.
Accessibility
Breadcrumbs implements the WAI-ARIA breadcrumb pattern.
What you must do
- Give each
<Breadcrumbs>a uniquearia-labelwhen a page renders more than one — duplicate "Breadcrumb" landmarks are indistinguishable to screen-reader users. - Set a crumb's
aria-labelonly when its visible children aren't a sufficient name, such as icon-only.
API reference
BreadCrumbs
| Prop | Type | Description |
|---|---|---|
| size | "xxs" | "xs" | "sm" | "md" | "lg" default: "md" | |
| maxItems | number | Caps how many crumbs stay visible even when there is room |
| ellipsisLabel | string default: "Show collapsed" | The aria-label of the ellipsis menu trigger, if one is rendered. |
| aria-label | string default: "Breadcrumb" |
BreadCrumbs.Item
| Prop | Type | Description |
|---|---|---|
| iconName | "function" | "filter" | "at" | "circle" | … 137 more | Optional icon to display |
| tooltip | string | Additional tooltip content for the crumb while it is visible in the trail. |
| tooltipOptions | Omit<BaseTooltipProps & { variant?: "light" | "dark"; }, "children" | "content"> | Options forwarded to the tooltip shown when tooltip is set |
| aria-label | string | Accessible name for the crumb, for when the visible children alone are not a sufficient label (e.g. icon-only or heavily abbreviated crumbs). |
| href | string | |
| onClick | (() => void) | |
| subItems | ItemOrGroup<BreadcrumbSubItem>[] | Turns the crumb into a dropdown-menu trigger listing these entries |
| maxWidth | MaxWidth<string | number> | Caps the crumb's width while it is visible in the trail |
| collapsedChildren | ReactNode | Rendered instead of children when the crumb is collapsed into the ellipsis menu — e.g. to show a shorter or richer label there. |
| noCollapse | boolean | Keeps the crumb visible in place: it is never collapsed into the ellipsis menu, even under width pressure or a maxItems cap. |
BreadcrumbSubItem
The shape of a crumb's subItems entries, shown in its dropdown. Each takes
children plus at most one of href or onClick.
| Prop | Type | Description |
|---|---|---|
| iconName | "function" | "filter" | "at" | "circle" | … 137 more | Optional icon to display |
| tooltip | string | Additional tooltip content for the crumb while it is visible in the trail. |
| tooltipOptions | Omit<BaseTooltipProps & { variant?: "light" | "dark"; }, "children" | "content"> | Options forwarded to the tooltip shown when tooltip is set |
| aria-label | string | Accessible name for the crumb, for when the visible children alone are not a sufficient label (e.g. icon-only or heavily abbreviated crumbs). |
| href | string | |
| onClick | (() => void) | |
| subItems | ItemOrGroup<BreadcrumbSubItem>[] | Turns the crumb into a dropdown-menu trigger listing these entries |
Was this page helpful?