Light

Breadcrumb

Displays the path to the current resource using a hierarchy of links.

Spec · from metadata

When to use

  • Showing hierarchical navigation path
  • Multi-level page structure where users may want to navigate up
  • Content-heavy sites with deep page hierarchies

When not to use

  • Flat site structure with no hierarchy
  • Step-by-step wizard — use Stepper or Tabs instead
  • Primary navigation — use NavigationMenu instead

Anti-patterns

Avoid<Breadcrumb>
  <BreadcrumbItem>
    <BreadcrumbLink href="/home">Home</BreadcrumbLink>
  </BreadcrumbItem>
  <BreadcrumbItem>
    <BreadcrumbLink href="/current">Current</BreadcrumbLink>
  </BreadcrumbItem>
</Breadcrumb>
Prefer<Breadcrumb>
  <BreadcrumbList>
    <BreadcrumbItem>
      <BreadcrumbLink href="/home">Home</BreadcrumbLink>
    </BreadcrumbItem>
    <BreadcrumbSeparator />
    <BreadcrumbItem>
      <BreadcrumbPage>Current</BreadcrumbPage>
    </BreadcrumbItem>
  </BreadcrumbList>
</Breadcrumb>

Wrap items in BreadcrumbList, add separators between items, and use BreadcrumbPage for the last item.

Accessibility

  • Required ARIAaria-label='breadcrumb' (set automatically)
  • Screen readerRenders as <nav aria-label='breadcrumb'>. BreadcrumbPage uses aria-current='page'. Separators and ellipsis are aria-hidden.
  • ContrastLinks use text-muted-foreground with hover:text-foreground. Current page uses text-foreground.

Token bindings

TokenCategoryUsage
muted-foregroundcolorLink text and separator color
foregroundcolorCurrent page text and link hover

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

VariantUse ForText Color
LinkNavigable ancestor pagestext-muted-foreground
Link CurrentCurrent page (last item)text-foreground
DropdownSwitch the segment to a sibling (peer page at the same level)text-muted-foreground + ChevronDown
EllipsisCollapsed middle itemsEllipsis icon, text-muted-foreground

Styling

Typography

PropertyValue
Fontfont-sans (Adelle Sans Regular)
Sizetext-sm (14px)
Weightfont-normal
Line Heightleading-5 (20px)

Dropdown Item

PropertyValue
Gapgap-1 (4px) between text and icon
Text Overflowtruncate (ellipsis on overflow)
Border Radiusrounded-xs (2px) for focus state

Ellipsis Item

PropertyValue
Containersize-9 (36×36px)
Iconsize-4 (16px) centered

Separators

TypeIconSizeColor
Chevron (default)ChevronRightsize-[15px]text-muted-foreground
SlashSlashsize-4text-muted-foreground

Icons

Separator: size-[15px] (15px) Dropdown/Ellipsis: size-4 (16px) Color: text-muted-foreground (#646565)

IconUse For
ChevronRightDefault separator
SlashAlternative separator
ChevronDownDropdown indicator
EllipsisCollapsed items

States

StateText ColorImplementation
Defaulttext-muted-foregroundBase appearance, no underline
Hovertext-foreground + underlinehover:text-foreground hover:underline underline-offset-4
Focustext-foregroundFocus ring with rounded-xs
Currenttext-foregroundNon-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-foregroundforeground) 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) — not Button/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 — where Parent is a BreadcrumbLink back to the section landing and Child is the current page as a BreadcrumbPage.

Maximum depth is two levels. Never prepend the platform/product name as a leading crumb. A child breadcrumb is always Parent > Childnever 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 is Self-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 with aria-label="Breadcrumb"
  • Use <ol> for the list structure
  • Mark current page with aria-current="page"
  • Ellipsis should be focusable and expandable

Gotchas

ProblemSolution
Last item clickableUse BreadcrumbPage not BreadcrumbLink for current
Separator after last itemDon't add separator after current page
Dropdown not styledAdd text-sm text-muted-foreground to DropdownMenuTrigger
Too many itemsUse BreadcrumbEllipsis to collapse middle items
Ellipsis not centeredAdd size-9 container with flex items-center justify-center
ChevronDown wrong sizeUse size-[15px] not size-4 for dropdown chevron
Breadcrumb on the home/landing pageDon't render one — breadcrumbs appear on child pages only
Trail starts with the platform/product nameDrop it — a child trail is Parent > Child, never Platform > Parent > Child
Trail grows past two levelsCollapse to Parent > Child (use BreadcrumbEllipsis for intermediate levels)

See Also


Last updated: June 23, 2026