Skip to content

Breadcrumb

SM · 950B gzip budget

A landmark trail with the current page marked aria-current.

Category
Navigation
Budget
sm, single-purpose control
External runtime
React / React DOM only
axe fixtureSSR rendersource scanbundle budget

Preview

Live fixture
Preview locale

Try the component here. Locale-aware formatting and direction follow the selected language; example content and labels are not automatically translated. Overlay demos use interactive launchers.

Install

npx shadcn@latest add https://gear5-ui.vercel.app/r/breadcrumb.json

Copies the source into your project. Pulls in 2 shared registry items: sanitize, cn.

New here? Set up Tailwind and import aliases first →

Source & props

Edit on GitHub ↗

Prop types and inline documentation are included below. This is repository source; the installer rewrites shared imports for your project.

import { sanitizeHref } from "../lib/sanitize";
import { cn } from "../lib/cn";

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

export interface BreadcrumbProps {
  items: BreadcrumbItem[];
  /** Auto-mirrors under RTL: rendered via `rtl:` variants, not hardcoded. */
  separator?: string;
  className?: string;
}

/**
 * `<nav aria-label="Breadcrumb">` around an ordered list, with the current
 * page marked `aria-current="page"` — the separator is decorative and
 * `aria-hidden`, so a screen reader hears "Home, Products, current page:
 * Shoes" instead of a stream of ">" characters.
 */
export function Breadcrumb({ items, separator = "/", className }: BreadcrumbProps) {
  return (
    <nav aria-label="Breadcrumb" className={className}>
      <ol className="flex flex-wrap items-center gap-1.5 text-sm text-neutral-600 dark:text-neutral-400">
        {items.map((item, index) => {
          const isLast = index === items.length - 1;

          return (
            <li key={`${item.label}-${index}`} className="flex items-center gap-1.5">
              {item.href && !isLast ? (
                <a href={sanitizeHref(item.href)} className="hover:text-neutral-900 hover:underline dark:hover:text-neutral-100">
                  {item.label}
                </a>
              ) : (
                <span aria-current={isLast ? "page" : undefined} className={cn(isLast && "font-medium text-neutral-900 dark:text-neutral-100")}>
                  {item.label}
                </span>
              )}
              {!isLast && (
                <span aria-hidden="true" className="text-neutral-400">
                  {separator}
                </span>
              )}
            </li>
          );
        })}
      </ol>
    </nav>
  );
}

What CI checks

Quality contract
  • Bundled, minified and gzipped against its tier budget
  • Audited by axe in the state previewed above
  • Rendered through react-dom/server with no browser globals
  • Scanned for network calls, dangerous sinks, and unguarded animation