Breadcrumbs

Material Design 3 breadcrumbs component for navigation hierarchy

Breadcrumbs

Breadcrumbs represent an ordered hierarchy. Put the list inside a labeled nav, mark the current page with aria-current="page", and hide visual separators from assistive technology. Long paths can use .breadcrumbs-nowrap for horizontal scrolling; a collapsed-path button must open an application-owned list of the omitted ancestors and remain keyboard operable.

Semantic hierarchy

Breadcrumbs show the current location within a navigational hierarchy. They help users understand where they are and provide quick access to parent pages.

Basic Usage

Basic Breadcrumbs

Separator Variants

Choose from different separator styles to match your design:

Slash Separator (Default)

Slash Separator

Chevron Separator

Chevron Separator

Dot Separator

Dot Separator

Arrow Separator

Arrow Separator

Add icons to breadcrumb items for better visual clarity:

Breadcrumbs with Icons

Home Icon Only

A common pattern uses just an icon for the home link to save space:

Home Icon Only

Color Variants

Use color variants to highlight active breadcrumbs:

Primary

Primary Color

Secondary

Secondary Color

Tertiary

Tertiary Color

Size Variants

Adjust breadcrumb sizes for different layouts:

Small

Small Size

Default

Default Size

Large

Large Size

Contained Variant

Add background container for emphasis:

Contained Breadcrumbs

No Wrap Variant

Prevent wrapping for horizontal scrolling:

No Wrap Breadcrumbs

Collapsed Breadcrumbs (with Ellipsis)

For long navigation paths, use ellipsis to show only key items:

Collapsed Breadcrumbs

Disabled State

Mark breadcrumb items as disabled:

Disabled Breadcrumb Item

Best Practices

Hierarchy Representation

Use breadcrumbs to show the hierarchical structure of your site:

Hierarchy Representation

Maximum Items

For deep hierarchies, collapse middle items:

Maximum Items with Ellipsis

Accessibility

  • Use semantic <nav> element with aria-label
  • Provide meaningful link text
  • Mark current page as aria-current="page"
  • Ensure sufficient color contrast

Accessible Breadcrumbs

Mobile Considerations

Use smaller sizes and no-wrap variant for mobile:

Mobile-Optimized Breadcrumbs

Framework Examples

React

interface BreadcrumbItem {
  label: string;
  href?: string;
  icon?: React.ReactNode;
}

interface BreadcrumbsProps {
  items: BreadcrumbItem[];
  separator?: 'slash' | 'chevron' | 'dot' | 'arrow';
  size?: 'sm' | 'md' | 'lg';
  color?: 'primary' | 'secondary' | 'tertiary';
  contained?: boolean;
  maxItems?: number;
}

export function Breadcrumbs({
  items,
  separator = 'slash',
  size,
  color,
  contained = false,
  maxItems
}: BreadcrumbsProps) {
  const displayItems = maxItems && items.length > maxItems
    ? [...items.slice(0, 1), { label: '...', collapsed: true }, ...items.slice(-2)]
    : items;

  const classes = [
    'breadcrumbs',
    `breadcrumbs-${separator}`,
    size && `breadcrumbs-${size}`,
    color && `breadcrumbs-${color}`,
    contained && 'breadcrumbs-contained'
  ].filter(Boolean).join(' ');

  return (
    <nav className={classes} aria-label="Breadcrumb navigation">
      {displayItems.map((item, index) => (
        <React.Fragment key={index}>
          {item.collapsed ? (
            <button className="breadcrumb-ellipsis" aria-label="Show more breadcrumbs" />
          ) : item.href ? (
            <a href={item.href} className="breadcrumb-link">
              {item.icon}
              {item.label}
            </a>
          ) : (
            <span className="breadcrumb-item breadcrumb-item-active" aria-current="page">
              {item.icon}
              {item.label}
            </span>
          )}
          {index < displayItems.length - 1 && (
            <span className="breadcrumb-separator" aria-hidden="true"></span>
          )}
        </React.Fragment>
      ))}
    </nav>
  );
}

// Usage
<Breadcrumbs
  items={[
    { label: 'Home', href: '/' },
    { label: 'Docs', href: '/docs' },
    { label: 'Components' }
  ]}
  separator="chevron"
  color="primary"
/>

Vue

<template>
  <nav :class="classes" aria-label="Breadcrumb navigation">
    <template v-for="(item, index) in displayItems" :key="index">
      <button
        v-if="item.collapsed"
        class="breadcrumb-ellipsis"
        aria-label="Show more breadcrumbs"
        @click="expandAll"
      />
      <a
        v-else-if="item.href"
        :href="item.href"
        class="breadcrumb-link"
      >
        <component v-if="item.icon" :is="item.icon" class="breadcrumb-icon" />
        {{ item.label }}
      </a>
      <span
        v-else
        class="breadcrumb-item breadcrumb-item-active"
        aria-current="page"
      >
        <component v-if="item.icon" :is="item.icon" class="breadcrumb-icon" />
        {{ item.label }}
      </span>
      <span
        v-if="index < displayItems.length - 1"
        class="breadcrumb-separator"
        aria-hidden="true"
      />
    </template>
  </nav>
</template>

<script setup>
import { computed, ref } from 'vue'

const props = defineProps({
  items: {
    type: Array,
    required: true
  },
  separator: {
    type: String,
    default: 'slash',
    validator: (value) => ['slash', 'chevron', 'dot', 'arrow'].includes(value)
  },
  size: {
    type: String,
    validator: (value) => ['sm', 'md', 'lg'].includes(value)
  },
  color: {
    type: String,
    validator: (value) => ['primary', 'secondary', 'tertiary'].includes(value)
  },
  contained: {
    type: Boolean,
    default: false
  },
  maxItems: Number
})

const expanded = ref(false)

const displayItems = computed(() => {
  if (!props.maxItems || props.items.length <= props.maxItems || expanded.value) {
    return props.items
  }
  return [
    props.items[0],
    { label: '...', collapsed: true },
    ...props.items.slice(-2)
  ]
})

const classes = computed(() => {
  return [
    'breadcrumbs',
    `breadcrumbs-${props.separator}`,
    props.size && `breadcrumbs-${props.size}`,
    props.color && `breadcrumbs-${props.color}`,
    props.contained && 'breadcrumbs-contained'
  ].filter(Boolean).join(' ')
})

const expandAll = () => {
  expanded.value = true
}
</script>

<!-- Usage -->
<Breadcrumbs
  :items="[
    { label: 'Home', href: '/' },
    { label: 'Docs', href: '/docs' },
    { label: 'Components' }
  ]"
  separator="chevron"
  color="primary"
  :max-items="3"
/>

API Reference

Class Names

Class Description
.breadcrumbs Base breadcrumbs container (required)
.breadcrumb-item Individual breadcrumb item
.breadcrumb-link Clickable breadcrumb link
.breadcrumb-item-active Current/active breadcrumb item
.breadcrumb-separator Separator between items
.breadcrumb-icon Icon within breadcrumb item
.breadcrumb-ellipsis Collapsed items button
.breadcrumb-item-disabled Disabled breadcrumb item

Separator Variants

Class Description
.breadcrumbs-slash Slash separator (/)
.breadcrumbs-chevron Chevron separator (›)
.breadcrumbs-dot Dot separator (•)
.breadcrumbs-arrow Arrow separator (→)

Color Variants

Class Description
.breadcrumbs-primary Primary color for hover/active
.breadcrumbs-secondary Secondary color for hover/active
.breadcrumbs-tertiary Tertiary color for hover/active

Size Variants

Class Description
.breadcrumbs-sm Small breadcrumbs (0.813rem)
.breadcrumbs-md Default breadcrumbs (0.875rem)
.breadcrumbs-lg Large breadcrumbs (1rem)

Layout Variants

Class Description
.breadcrumbs-contained Breadcrumbs with background container
.breadcrumbs-nowrap Prevent wrapping, enable horizontal scroll

Combinations

Contained with Chevron and Primary Color

Large with Arrow and No Wrap

See Also