Import
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
} from "@timelycare/helix-ui"
Props
interface BreadcrumbProps {
children: React.ReactNode
separator?: React.ReactNode
className?: string
}
interface BreadcrumbListProps {
children: React.ReactNode
className?: string
}
interface BreadcrumbItemProps {
children: React.ReactNode
className?: string
}
interface BreadcrumbLinkProps {
href: string
children: React.ReactNode
className?: string
}
interface BreadcrumbPageProps {
children: React.ReactNode
className?: string
}
interface BreadcrumbSeparatorProps {
children?: React.ReactNode
className?: string
}
interface BreadcrumbEllipsisProps {
className?: string
}
Variants
| Variant | Use For | Text Color |
|---|---|---|
Link | Navigable ancestor pages | text-muted-foreground |
Link Current | Current page (last item) | text-foreground |
Dropdown | Switch the segment to a sibling (peer page at the same level) | text-muted-foreground + ChevronDown |
Ellipsis | Collapsed middle items | Ellipsis icon, text-muted-foreground |
Styling
Typography
| Property | Value |
|---|---|
| Font | font-sans (Adelle Sans Regular) |
| Size | text-sm (14px) |
| Weight | font-normal |
| Line Height | leading-5 (20px) |
Dropdown Item
| Property | Value |
|---|---|
| Gap | gap-1 (4px) between text and icon |
| Text Overflow | truncate (ellipsis on overflow) |
| Border Radius | rounded-xs (2px) for focus state |
Ellipsis Item
| Property | Value |
|---|---|
| Container | size-9 (36×36px) |
| Icon | size-4 (16px) centered |
Separators
| Type | Icon | Size | Color |
|---|---|---|---|
| Chevron (default) | ChevronRight | size-[15px] | text-muted-foreground |
| Slash | Slash | size-4 | text-muted-foreground |
Icons
Separator: size-[15px] (15px)
Dropdown/Ellipsis: size-4 (16px)
Color: text-muted-foreground (#646565)
| Icon | Use For |
|---|---|
ChevronRight | Default separator |
Slash | Alternative separator |
ChevronDown | Dropdown indicator |
Ellipsis | Collapsed items |
States
| State | Text Color | Implementation |
|---|---|---|
| Default | text-muted-foreground | Base appearance, no underline |
| Hover | text-foreground + underline | hover:text-foreground hover:underline underline-offset-4 |
| Focus | text-foreground | Focus ring with rounded-xs |
| Current | text-foreground | Non-clickable, last item — no hover treatment |
Hover affordance: Breadcrumb links follow the same hover pattern as the text link button variant — on hover they shift color (
muted-foreground→foreground) and reveal an underline (underline-offset-4). The current page (BreadcrumbPage) is non-interactive and never shows the color shift or underline.
Common Patterns
Basic
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
With Ellipsis
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbEllipsis className="size-9" />
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Current</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
With Dropdown
A dropdown on a breadcrumb segment lets the user switch that segment to one of its siblings — other pages at the same level of the hierarchy. The menu lists peers of the segment the dropdown is attached to, not that segment's children.
In the trail
Home > Components > Breadcrumb, the dropdown on Components lists peers of Components (e.g.Tokens,Patterns,Rules) — notButton/Card(those are children of Components, i.e. siblings of the current page). Selecting a peer navigates to that section at the same level.
import { ChevronDown } from "lucide-react"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@timelycare/helix-ui"
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
{/* Dropdown is attached to "Components" → list Components' SIBLINGS */}
<DropdownMenu>
<DropdownMenuTrigger className="flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground">
Components
<ChevronDown className="size-[15px]" />
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem>Tokens</DropdownMenuItem>
<DropdownMenuItem>Patterns</DropdownMenuItem>
<DropdownMenuItem>Rules</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
Breadcrumb with Page Title
Navigation context above page headings.
<div className="space-y-2">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/settings">Settings</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Profile</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<h1 className="text-3xl font-semibold">Profile Settings</h1>
</div>
Custom Separator (Slash)
import { Slash } from "lucide-react"
<BreadcrumbSeparator>
<Slash className="size-4" />
</BreadcrumbSeparator>
Component Structure
{/* Breadcrumb container */}
<nav aria-label="Breadcrumb">
<ol className="flex items-center">
{/* BreadcrumbItem - Link */}
<li className="flex items-center">
<a href="/" className="text-sm text-muted-foreground hover:text-foreground">
Home
</a>
</li>
{/* BreadcrumbSeparator */}
<li className="flex items-center">
<ChevronRight className="size-[15px] text-muted-foreground" />
</li>
{/* BreadcrumbItem - Ellipsis */}
<li className="flex size-9 items-center justify-center">
<Ellipsis className="size-4 text-muted-foreground" />
</li>
{/* BreadcrumbItem - Dropdown */}
<li className="flex items-center gap-1 text-sm text-muted-foreground">
Components
<ChevronDown className="size-[15px]" />
</li>
{/* BreadcrumbItem - Current Page */}
<li className="flex items-center">
<span className="text-sm text-foreground">
Current
</span>
</li>
</ol>
</nav>
Header Integration
The Breadcrumb component is used inside the Header to display navigation context. The breadcrumb content is driven by sidebar navigation state.
Navigation model
Breadcrumbs are a child-page-only affordance. They communicate "where this page sits under its parent" — nothing more.
- Root / platform home: No breadcrumb. The home page never renders a breadcrumb (there is nowhere up to go).
- Parent / section landing: No breadcrumb. A top-level section's own landing page does not show a breadcrumb.
- Child page: Render exactly two levels —
Parent > Child— whereParentis aBreadcrumbLinkback to the section landing andChildis the current page as aBreadcrumbPage.
Maximum depth is two levels. Never prepend the platform/product name as a leading crumb. A child breadcrumb is always Parent > Child — never Platform Name > Parent > Child. Even for pages nested more deeply, collapse to Parent > Child (use BreadcrumbEllipsis if an intermediate level must be represented) rather than growing the trail with the platform root.
⚠️ Common product mistake: prefixing the trail with the platform/product name (e.g.
TimelyCare > Self-Care > Breathwork). The platform name is not a breadcrumb level. The correct trail isSelf-Care > Breathwork.
Example: Header breadcrumb with active nav
{/* Child page — the ONLY case that renders a breadcrumb. */}
{/* Correct: Parent > Child (two levels, no platform prefix). */}
<Breadcrumb className="flex-1">
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/self-care">Self-Care</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breathwork</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
{/* Root / platform home AND parent / section landing: render NOTHING. */}
{/* Do not render a single-item "Home" breadcrumb on these pages. */}
Mobile behavior
On mobile, breadcrumbs appear in a separate row below the main header bar (inside <div className="px-4 py-4">), since the main bar is reserved for the hamburger, logo, and icon buttons.
Accessibility
- Use
<nav>element witharia-label="Breadcrumb" - Use
<ol>for the list structure - Mark current page with
aria-current="page" - Ellipsis should be focusable and expandable
Gotchas
| Problem | Solution |
|---|---|
| Last item clickable | Use BreadcrumbPage not BreadcrumbLink for current |
| Separator after last item | Don't add separator after current page |
| Dropdown not styled | Add text-sm text-muted-foreground to DropdownMenuTrigger |
| Too many items | Use BreadcrumbEllipsis to collapse middle items |
| Ellipsis not centered | Add size-9 container with flex items-center justify-center |
| ChevronDown wrong size | Use size-[15px] not size-4 for dropdown chevron |
| Breadcrumb on the home/landing page | Don't render one — breadcrumbs appear on child pages only |
| Trail starts with the platform/product name | Drop it — a child trail is Parent > Child, never Platform > Parent > Child |
| Trail grows past two levels | Collapse to Parent > Child (use BreadcrumbEllipsis for intermediate levels) |
See Also
- Related Components: Header (app header with breadcrumbs), Navigation Menu (primary navigation), Pagination (sequential navigation)
- Accessibility: Navigation Accessibility — Breadcrumb ARIA patterns
Last updated: June 23, 2026