Skip to content
    Style: Wireframe

    Components · Navigation

    Breadcrumb

    Where the page sits: a nav with an ordered list and the current page marked.

    38% of the 2,073 sites in The UI Index have a navigation (790 sites).

    Used in UI Pro: Page header, Case header, Breadcrumb

    Both previews render the same markup; the HTML tab below is that markup without a framework.

    Install

    React
    npx shadcn@latest add https://www.themes.dev/ui/r/breadcrumb.json
    Astro
    npx shadcn@latest add https://www.themes.dev/ui/r/astro/breadcrumb.json

    Or copy the files below into your project. They need clsx, tailwind-merge, and the themes.dev UI theme. The HTML needs only the compiled CSS.

    breadcrumb.tsx
    import { breadcrumb, SEPARATOR_PATH, type Crumb } from './breadcrumb.variants';
    
    export type { Crumb };
    
    export interface BreadcrumbProps {
      /** From the top down; the last one is the current page (its href is ignored). */
      items: Crumb[];
      label?: string;
      className?: string;
    }
    
    /** A breadcrumb trail: nav > ol, the current page with aria-current, separators in CSS. */
    export function Breadcrumb({ items, label = 'Breadcrumb', className }: BreadcrumbProps) {
      return (
        <nav aria-label={label} className={className}>
          <ol className={breadcrumb.list}>
            {items.map((c, k) => (
              <li key={k} className={breadcrumb.item}>
                {k === items.length - 1 ? <span aria-current="page" className={breadcrumb.current}>{c.label}</span> : <a href={c.href} className={breadcrumb.link}>{c.label}</a>}
                {k < items.length - 1 && (
                  <span className={breadcrumb.separator}>
                    <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d={SEPARATOR_PATH} /></svg>
                  </span>
                )}
              </li>
            ))}
          </ol>
        </nav>
      );
    }
    breadcrumb.variants.ts
    /** Where the page sits: a nav with an ordered list, the current page last with aria-current. The separators are
     *  hidden from screen readers (aria-hidden). */
    export const breadcrumb = {
      list: 'm-0 flex list-none flex-wrap items-center gap-x-1.5 gap-y-1 p-0 text-sm text-muted-foreground',
      // The separator belongs to the crumb before it, so a wrapped trail never starts a line with one.
      item: 'inline-flex items-center gap-1.5 whitespace-nowrap',
      separator: 'inline-flex text-muted-foreground/70 [&_svg]:size-3.5',
      link: '-mx-1 inline-flex min-h-6 items-center rounded-sm px-1 transition-colors hover:text-foreground hover:underline hover:underline-offset-4 active:text-foreground/70',
      current: 'font-medium text-foreground',
    };
    
    export type Crumb = { label: string; href?: string };
    export const SEPARATOR_PATH = 'M6 3.5l4.5 4.5L6 12.5';