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

RoleTarget ElementDescription
navigation<nav> elementProvides a navigation landmark for assistive technology (implicit role of <nav>)

WAI-ARIA Properties

aria-label

Labels the navigation landmark for screen readers

Values
Breadcrumb (or localized)
Required
Yes

aria-current

Identifies the current page within the breadcrumb trail

Values
page
Required
Yes (on last item)

WAI-ARIA States

aria-current

Target Element

Last item in the breadcrumb (current page)

Values
page
Required
Yes
Change Trigger

Indicates the current page location within the breadcrumb navigation.

Keyboard Support

KeyAction
TabMove focus between breadcrumb links
EnterActivate the focused link
  • Breadcrumb uses native <a> element behavior for keyboard interaction. No additional keyboard handlers are required.

References

Source Code

Breadcrumb.vue
<script setup lang="ts">
/**
 * Breadcrumb component following WAI-ARIA APG pattern
 * @see https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/
 */

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

export interface BreadcrumbProps {
  items: BreadcrumbItem[];
  ariaLabel?: string;
  class?: string;
}

const props = withDefaults(defineProps<BreadcrumbProps>(), {
  ariaLabel: 'Breadcrumb',
});

function getItemKey(item: BreadcrumbItem): string {
  return `${item.href ?? 'current'}-${item.label}`;
}
</script>

<template>
  <nav v-if="items.length > 0" :aria-label="ariaLabel" :class="['apg-breadcrumb', props.class]">
    <ol class="apg-breadcrumb-list">
      <li v-for="(item, index) in items" :key="getItemKey(item)" class="apg-breadcrumb-item">
        <a
          v-if="item.href && index !== items.length - 1"
          :href="item.href"
          class="apg-breadcrumb-link"
        >
          {{ item.label }}
        </a>
        <span
          v-else
          :aria-current="index === items.length - 1 ? 'page' : undefined"
          class="apg-breadcrumb-current"
        >
          {{ item.label }}
        </span>
      </li>
    </ol>
  </nav>
</template>

Usage

Example
<script setup>
import Breadcrumb from './Breadcrumb.vue';

const items = [
  { label: 'Home', href: '/' },
  { label: 'Products', href: '/products' },
  { label: 'Current Product' }
];
</script>

<template>
  <Breadcrumb :items="items" />
</template>

API

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

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

Test Description
nav element Uses semantic <nav> element
aria-label Navigation has accessible label (default: "Breadcrumb")
aria-current="page" Last item has aria-current="page"
ol/li structure Uses ordered list for proper semantic structure

High Priority: Keyboard Interaction

Test Description
Tab navigation Tab moves focus between breadcrumb links
Enter activation Enter key activates focused link
Current page not focusable Last item (span) is not in tab order

Medium Priority: Accessibility

Test Description
axe violations No WCAG 2.1 AA violations (via jest-axe)
Custom aria-label Can override default label via ariaLabel prop
Separator hidden Visual separators are hidden from assistive technology

Low Priority: Component Behavior

Test Description
Renders all items All provided items are rendered in order
Links have href Non-current items render as links with correct href
className merge Custom classes are merged with component classes

Low Priority: Cross-framework Consistency

Test Description
All frameworks have nav React, Vue, Svelte, Astro all render breadcrumb navigation
Same item count All frameworks render the same number of breadcrumb items
Current page marked All frameworks mark the last item with aria-current="page"

Testing Tools

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

Resources