Agents (llms.txt)
Octocat

Breadcrumb

Hierarchical navigation showing the user's location within a site.

import { Breadcrumb } from '@/components/breadcrumb';

export default function BreadcrumbPreview() {
  return (
    <Breadcrumb>
      <Breadcrumb.List>
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">Home</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">Components</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
        </Breadcrumb.Item>
      </Breadcrumb.List>
    </Breadcrumb>
  );
}

Dependencies

Source Code

import { CaretRightIcon, DotsThreeIcon } from '@phosphor-icons/react/dist/ssr';

import { Slot } from '@/components/slot';
import { cn } from '@/lib/utils/classnames';

const Breadcrumb = ({
  ref,
  className,
  ...props
}: React.ComponentPropsWithRef<'nav'>) => {
  return (
    <nav
      ref={ref}
      aria-label="breadcrumb"
      className={cn('text-sm', className)}
      {...props}
    />
  );
};

const BreadcrumbList = ({
  ref,
  className,
  ...props
}: React.ComponentPropsWithRef<'ol'>) => {
  return (
    <ol
      ref={ref}
      className={cn(
        'wrap-break-word flex flex-wrap items-center gap-1.5 text-foreground-secondary sm:gap-2.5',
        className
      )}
      {...props}
    />
  );
};

const BreadcrumbItem = ({
  ref,
  className,
  ...props
}: React.ComponentPropsWithRef<'li'>) => {
  return (
    <li
      ref={ref}
      className={cn('inline-flex items-center gap-1.5', className)}
      {...props}
    />
  );
};

interface BreadcrumbLinkProps extends React.ComponentPropsWithRef<'a'> {
  asChild?: boolean;
}

const BreadcrumbLink = ({
  ref,
  className,
  asChild,
  ...props
}: BreadcrumbLinkProps) => {
  const Comp = asChild ? Slot : 'a';

  return (
    <Comp
      ref={ref}
      className={cn(
        'focus-visible:ring-(length:--ring-width) rounded-xs outline-none ring-ring transition hover:text-foreground',
        className
      )}
      {...props}
    />
  );
};

interface BreadcrumbPageProps extends React.ComponentPropsWithRef<'span'> {
  asChild?: boolean;
}

const BreadcrumbPage = ({
  ref,
  className,
  asChild,
  ...props
}: BreadcrumbPageProps) => {
  const Comp = asChild ? Slot : 'span';

  return (
    <Comp
      ref={ref}
      aria-current="page"
      className={cn('font-medium text-foreground', className)}
      {...props}
    />
  );
};

const BreadcrumbSeparator = ({
  className,
  children,
  ...props
}: React.ComponentPropsWithRef<'li'>) => {
  return (
    <li
      role="presentation"
      aria-hidden="true"
      className={cn('inline-flex items-center [&>svg]:size-3.5', className)}
      {...props}
    >
      {children ?? <CaretRightIcon />}
    </li>
  );
};

const BreadcrumbEllipsis = ({
  className,
  ...props
}: React.ComponentPropsWithRef<'span'>) => {
  return (
    <span
      role="presentation"
      aria-hidden="true"
      className={cn('flex size-5 items-center justify-center', className)}
      {...props}
    >
      <DotsThreeIcon className="size-4" />
    </span>
  );
};

const CompoundBreadcrumb = Object.assign(Breadcrumb, {
  List: BreadcrumbList,
  Item: BreadcrumbItem,
  Link: BreadcrumbLink,
  Page: BreadcrumbPage,
  Separator: BreadcrumbSeparator,
  Ellipsis: BreadcrumbEllipsis,
});

export { CompoundBreadcrumb as Breadcrumb };

Anatomy


          <Breadcrumb>
  <Breadcrumb.List>
    <Breadcrumb.Item>
      <Breadcrumb.Link />
    </Breadcrumb.Item>
    <Breadcrumb.Separator />
    <Breadcrumb.Item>
      <Breadcrumb.Ellipsis />
    </Breadcrumb.Item>
    <Breadcrumb.Separator />
    <Breadcrumb.Item>
      <Breadcrumb.Page />
    </Breadcrumb.Item>
  </Breadcrumb.List>
</Breadcrumb>
        

API Reference

Extends the nav element. Renders with aria-label="breadcrumb".

Extends the ol element. Ordered list — the order is meaningful and read out by screen readers.

Extends the li element.

Extends the a element.

Prop Default Type Description
asChild - boolean Use to compose with a router-aware Link component.

Extends the span element. Represents the current page — not a navigable target. Renders with aria-current="page" per the WAI-ARIA Breadcrumb pattern.

Prop Default Type
asChild - boolean

Extends the li element. Decorative — rendered with role="presentation" and aria-hidden="true". Defaults to a chevron icon. Pass children to override (e.g., /, >, or any element).

Extends the span element. Decorative collapse indicator. Combine with a Menu (or any disclosure) to expand the hidden segments.

Examples

With an icon

Replace the first segment’s label with an icon (commonly a home glyph). Pair it with aria-label so the link still announces meaningfully.

import { HouseIcon } from '@phosphor-icons/react/dist/ssr';

import { Breadcrumb } from '@/components/breadcrumb';

export default function BreadcrumbIconPreview() {
  return (
    <Breadcrumb>
      <Breadcrumb.List>
        <Breadcrumb.Item>
          <Breadcrumb.Link
            href="#"
            aria-label="Home"
            className="inline-flex items-center"
          >
            <HouseIcon className="size-4" />
          </Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">Components</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
        </Breadcrumb.Item>
      </Breadcrumb.List>
    </Breadcrumb>
  );
}

Custom separator

import { Breadcrumb } from '@/components/breadcrumb';

export default function BreadcrumbCustomSeparatorPreview() {
  return (
    <Breadcrumb>
      <Breadcrumb.List>
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">Docs</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator>/</Breadcrumb.Separator>
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">UI</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator>/</Breadcrumb.Separator>
        <Breadcrumb.Item>
          <Breadcrumb.Page>Breadcrumb</Breadcrumb.Page>
        </Breadcrumb.Item>
      </Breadcrumb.List>
    </Breadcrumb>
  );
}

Collapsed with dropdown

When the trail is too long, replace middle segments with Breadcrumb.Ellipsis inside a Menu so they remain reachable.

import { Breadcrumb } from '@/components/breadcrumb';
import { Menu } from '@/components/menu';

export default function BreadcrumbCollapsedPreview() {
  return (
    <Breadcrumb>
      <Breadcrumb.List>
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">Home</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Menu>
            <Menu.Trigger asChild>
              <button
                type="button"
                aria-label="More breadcrumbs"
                className="cursor-pointer hover:text-foreground"
              >
                <Breadcrumb.Ellipsis />
              </button>
            </Menu.Trigger>
            <Menu.Items>
              <Menu.Item>Components</Menu.Item>
              <Menu.Item>Navigation</Menu.Item>
              <Menu.Item>Lists</Menu.Item>
            </Menu.Items>
          </Menu>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Breadcrumb.Link href="#">Breadcrumb</Breadcrumb.Link>
        </Breadcrumb.Item>
        <Breadcrumb.Separator />
        <Breadcrumb.Item>
          <Breadcrumb.Page>Collapsed</Breadcrumb.Page>
        </Breadcrumb.Item>
      </Breadcrumb.List>
    </Breadcrumb>
  );
}

Best Practices

  1. Usage:

    • The last item should be Breadcrumb.Page, not Breadcrumb.Link — it’s the current location.
    • Keep labels short. Truncate long names with text-ellipsis and a fixed max-w-* rather than wrapping mid-word.
  2. Accessibility:

    • The <nav aria-label="breadcrumb"> and ordered <ol> are required for screen readers to announce the trail correctly.
    • Separators are decorative — never put meaningful content inside Breadcrumb.Separator.
  3. Routing:

    • Use asChild on Breadcrumb.Link to compose with next/link, <a is="astro-link">, or any router-aware component.

Previous

Badge

Next

Button