APG Patterns
日本語
日本語

Breadcrumb

A navigation pattern that shows the user's current location within a site hierarchy.

Demo

Basic Breadcrumb

A simple breadcrumb trail showing the path to the current page.

Long Path

A deeper navigation path with multiple levels of hierarchy.

Open demo only →

Accessibility Features

WAI-ARIA Roles

Role Target Element Description
navigation <nav> element Provides a navigation landmark for assistive technology (implicit role of

WAI-ARIA Breadcrumb Pattern (opens in new tab)

WAI-ARIA Properties

Attribute Target Values Required Description
aria-label <nav> "Breadcrumb" (or localized) Yes Labels the navigation landmark for screen readers
aria-current Current page element "page" Yes (on last item) Identifies the current page within the breadcrumb trail

WAI-ARIA States

aria-current=""page""

Indicates the current page location within the breadcrumb navigation.

Target Last item in the breadcrumb (current page)
Values "page"
Required Yes
Reference aria-current (opens in new tab)

Keyboard Support

Key Action
Tab Move focus between breadcrumb links
Enter Activate the focused link

Breadcrumb uses native element behavior for keyboard interaction. No additional keyboard handlers are required.

Source Code

Breadcrumb.tsx
import { cn } from '@/lib/utils';

/**
 * Represents a single item in the breadcrumb trail
 */
export interface BreadcrumbItem {
  /**
   * Display text for the breadcrumb item
   */
  label: string;
  /**
   * URL for the breadcrumb link. If omitted, renders as non-interactive text.
   */
  href?: string;
}

/**
 * Props for the Breadcrumb component
 *
 * @see https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/
 *
 * @example
 * ```tsx
 * <Breadcrumb
 *   items={[
 *     { label: 'Home', href: '/' },
 *     { label: 'Products', href: '/products' },
 *     { label: 'Current Page' }
 *   ]}
 * />
 * ```
 */
export interface BreadcrumbProps {
  /**
   * Array of breadcrumb items representing the navigation path
   */
  items: BreadcrumbItem[];
  /**
   * Accessible label for the navigation landmark
   * @default "Breadcrumb"
   */
  ariaLabel?: string;
  /**
   * Additional CSS class to apply to the nav element
   */
  className?: string;
}

export function Breadcrumb({
  items,
  ariaLabel = 'Breadcrumb',
  className,
}: BreadcrumbProps): React.ReactElement | null {
  if (items.length === 0) {
    return null;
  }

  return (
    <nav aria-label={ariaLabel} className={cn('apg-breadcrumb', className)}>
      <ol className="apg-breadcrumb-list">
        {items.map((item, index) => {
          const isLast = index === items.length - 1;
          const key = `${item.href ?? 'current'}-${item.label}`;

          return (
            <li key={key} className="apg-breadcrumb-item">
              {item.href && !isLast ? (
                <a href={item.href} className="apg-breadcrumb-link">
                  {item.label}
                </a>
              ) : (
                <span aria-current={isLast ? 'page' : undefined} className="apg-breadcrumb-current">
                  {item.label}
                </span>
              )}
            </li>
          );
        })}
      </ol>
    </nav>
  );
}

export default Breadcrumb;

Usage

Example
import { Breadcrumb } from './Breadcrumb';

function App() {
  return (
    <Breadcrumb
      items={[
        { label: 'Home', href: '/' },
        { label: 'Products', href: '/products' },
        { label: 'Current Product' }
      ]}
    />
  );
}

API

BreadcrumbProps

Prop Type Default Description
items BreadcrumbItem[] required Array of breadcrumb items
ariaLabel string "Breadcrumb" Accessible label for the navigation
className string - Additional CSS class

BreadcrumbItem

Property Type Required Description
label string Yes Display text for the item
href string No URL for the link (omit for current page)

Testing

Tests verify APG compliance across ARIA attributes, semantic structure, and accessibility requirements. The Breadcrumb component uses a two-layer testing strategy.

Testing Strategy

Unit Tests (Testing Library)

Verify the component's rendered output using framework-specific testing libraries. These tests ensure correct HTML structure and ARIA attributes.

  • HTML structure (nav, ol, li elements)
  • ARIA attributes (aria-label, aria-current)
  • Link rendering and href values
  • Accessibility via jest-axe

E2E Tests (Playwright)

Verify component behavior in a real browser environment across all frameworks. These tests cover interactions and cross-framework consistency.

  • Keyboard navigation (Tab, Enter)
  • ARIA structure in live browser
  • axe-core accessibility scanning
  • Cross-framework consistency checks

Test Categories

High Priority: APG ARIA Attributes

TestDescription
nav elementUses semantic
aria-labelNavigation has accessible label (default: "Breadcrumb")
aria-current="page"Last item has aria-current="page"
ol/li structureUses ordered list for proper semantic structure

High Priority: Keyboard Interaction

TestDescription
Tab navigationTab moves focus between breadcrumb links
Enter activationEnter key activates focused link
Current page not focusableLast item (span) is not in tab order

Medium Priority: Accessibility

TestDescription
axe violationsNo WCAG 2.1 AA violations (via jest-axe)
Custom aria-labelCan override default label via ariaLabel prop
Separator hiddenVisual separators are hidden from assistive technology

Low Priority: Component Behavior

TestDescription
Renders all itemsAll provided items are rendered in order
Links have hrefNon-current items render as links with correct href
className mergeCustom classes are merged with component classes

Low Priority: Cross-framework Consistency

TestDescription
All frameworks have navReact, Vue, Svelte, Astro all render breadcrumb navigation
Same item countAll frameworks render the same number of breadcrumb items
Current page markedAll frameworks mark the last item with aria-current="page"

Testing Tools

See testing-strategy.md (opens in new tab) for full documentation.

Resources