Skip to content

NavigationBreadcrumb

Breadcrumb

The trail at the top of a long page. Used in case studies and articles; the design system uses the doc system rail instead.

Native <nav>Last item is the current pageChevron separator

Demo

Default

Anatomy

  • 0.8125 rem, --muted-foreground at rest, --foreground on hover
  • Chevron separator, 12 px, decorative
  • Last item: aria-current="page" and --foreground color
  • Wrapping: horizontal by default; on viewports below 480 px, wraps to two lines with no visual indication that it has wrapped

Implementation

breadcrumb.tsx
import Link from "next/link"
import { ChevronRight } from "lucide-react"
import SiteIcon from "@/components/site-icon"

interface BreadcrumbItem { label: string; href?: string }

export function Breadcrumb({ items }: { items: BreadcrumbItem[] }) {
  return (
    <nav aria-label="Breadcrumb" className="ds-breadcrumb">
      <ol className="ds-breadcrumb__list">
        {items.map((item, i) => {
          const isLast = i === items.length - 1
          return (
            <li key={item.label} className="ds-breadcrumb__item">
              {item.href && !isLast ? (
                <Link href={item.href} className="ds-breadcrumb__link">{item.label}</Link>
              ) : (
                <span aria-current={isLast ? "page" : undefined} className="ds-breadcrumb__current">
                  {item.label}
                </span>
              )}
              {!isLast ? (
                <SiteIcon icon={ChevronRight} size="xs" className="ds-breadcrumb__sep" />
              ) : null}
            </li>
          )
        })}
      </ol>
    </nav>
  )
}

Props

PropTypeDefaultDescription
items{ label: string; href?: string }[]NoneRequired: the trail