Breadcrumb
Displays the path to the current resource using a hierarchy of links.
Installation
npx shadcn@latest add breadcrumb
Usage
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
export function BreadcrumbDemo() {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink>Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink>Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}
Simple Example
Examples
Custom Separator
With Dropdown
Collapsed
With Icons
Variations
API Reference
Breadcrumb
The root breadcrumb navigation container.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes for styling. |
children | React.ReactNode | - | BreadcrumbList component. |
BreadcrumbList
The ordered list container for breadcrumb items.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes for styling. |
children | React.ReactNode | - | BreadcrumbItem components with separators. |
BreadcrumbItem
Individual breadcrumb item wrapper.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes for styling. |
children | React.ReactNode | - | BreadcrumbLink, BreadcrumbPage, or custom content. |
BreadcrumbLink
Navigational link within breadcrumb.
Prop | Type | Default | Description |
---|---|---|---|
asChild | boolean | false | Render as child component (useful for Next.js Link). |
href | string | - | Link destination (when not using asChild). |
className | string | - | Additional CSS classes for styling. |
children | React.ReactNode | - | Link text or content. |
BreadcrumbPage
Current page indicator (non-interactive).
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes for styling. |
children | React.ReactNode | - | Current page text or content. |
BreadcrumbSeparator
Visual separator between breadcrumb items.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes for styling. |
children | React.ReactNode | <ChevronRight /> | Custom separator content (icon or text). |
BreadcrumbEllipsis
Ellipsis indicator for collapsed breadcrumbs.
Prop | Type | Default | Description |
---|---|---|---|
className | string | - | Additional CSS classes for styling. |
Implementation Details
Architecture
Built with semantic HTML and ARIA attributes for accessibility:
- Navigation Landmark: Uses
<nav>
witharia-label="breadcrumb"
- Ordered List: Structured as
<ol>
for logical hierarchy - Current Page: Marked with
aria-current="page"
androle="link"
- Separators: Hidden from screen readers with
aria-hidden="true"
Component Structure
<Breadcrumb> {/* <nav aria-label="breadcrumb"> */}
<BreadcrumbList> {/* <ol> */}
<BreadcrumbItem> {/* <li> */}
<BreadcrumbLink /> {/* <a> or custom component */}
</BreadcrumbItem>
<BreadcrumbSeparator /> {/* <li role="presentation"> */}
<BreadcrumbItem>
<BreadcrumbPage /> {/* <span aria-current="page"> */}
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
Responsive Design
Breadcrumbs automatically wrap and scale:
- Text Wrapping: Uses
break-words
for long paths - Flexible Spacing: Responsive gap sizing (
gap-1.5
on mobile,gap-2.5
on desktop) - Icon Scaling: Separators sized appropriately (
size-3.5
)
Best Practices
Navigation Hierarchy
Structure breadcrumbs to reflect logical navigation:
// Good - Clear hierarchy
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/products">Products</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/products/laptops">Laptops</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>MacBook Pro</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
Link Integration
Use the asChild
prop for framework-specific routing:
import Link from "next/link"
<BreadcrumbLink asChild>
<Link href="/dashboard">Dashboard</Link>
</BreadcrumbLink>
Content Guidelines
- Keep labels concise: Use short, descriptive terms
- Avoid redundancy: Don't repeat the site name in every breadcrumb
- Use sentence case: Capitalize only the first letter
- Current page: Always use BreadcrumbPage for the current location
Common Use Cases
E-commerce Navigation
Product catalog and category navigation:
Documentation Site
Multi-level documentation navigation with icon home:
File System Navigation
File and folder navigation interface:
function FileBreadcrumb({ path }) {
const pathSegments = path.split('/').filter(Boolean)
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/files" className="flex items-center gap-2">
<HomeIcon className="size-4" />
Root
</Link>
</BreadcrumbLink>
</BreadcrumbItem>
{pathSegments.map((segment, index) => {
const isLast = index === pathSegments.length - 1
const href = `/files/${pathSegments.slice(0, index + 1).join('/')}`
return (
<React.Fragment key={index}>
<BreadcrumbSeparator />
<BreadcrumbItem>
{isLast ? (
<BreadcrumbPage className="flex items-center gap-2">
<FileIcon className="size-4" />
{segment}
</BreadcrumbPage>
) : (
<BreadcrumbLink asChild>
<Link href={href} className="flex items-center gap-2">
<FolderIcon className="size-4" />
{segment}
</Link>
</BreadcrumbLink>
)}
</BreadcrumbItem>
</React.Fragment>
)
})}
</BreadcrumbList>
</Breadcrumb>
)
}
Advanced Patterns
Responsive Breadcrumbs
Handle long navigation paths gracefully:
function ResponsiveBreadcrumb({ items, maxItems = 3 }) {
const [isExpanded, setIsExpanded] = useState(false)
if (items.length <= maxItems) {
return <NormalBreadcrumb items={items} />
}
const visibleItems = isExpanded
? items
: [items[0], ...items.slice(-2)]
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href={items[0].href}>{items[0].label}</Link>
</BreadcrumbLink>
</BreadcrumbItem>
{!isExpanded && items.length > maxItems && (
<>
<BreadcrumbSeparator />
<BreadcrumbItem>
<button
onClick={() => setIsExpanded(true)}
className="flex items-center gap-1"
>
<BreadcrumbEllipsis />
</button>
</BreadcrumbItem>
</>
)}
{/* Render remaining items */}
{visibleItems.slice(1).map((item, index) => (
<React.Fragment key={index}>
<BreadcrumbSeparator />
<BreadcrumbItem>
{item.href ? (
<BreadcrumbLink asChild>
<Link href={item.href}>{item.label}</Link>
</BreadcrumbLink>
) : (
<BreadcrumbPage>{item.label}</BreadcrumbPage>
)}
</BreadcrumbItem>
</React.Fragment>
))}
</BreadcrumbList>
</Breadcrumb>
)
}
Dynamic Breadcrumbs
Generate breadcrumbs from URL or route data:
function DynamicBreadcrumb() {
const pathname = usePathname()
const router = useRouter()
const breadcrumbItems = useMemo(() => {
const segments = pathname.split('/').filter(Boolean)
return segments.map((segment, index) => {
const href = '/' + segments.slice(0, index + 1).join('/')
const label = segment.charAt(0).toUpperCase() + segment.slice(1)
const isLast = index === segments.length - 1
return { href: isLast ? null : href, label, isLast }
})
}, [pathname])
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/">Home</Link>
</BreadcrumbLink>
</BreadcrumbItem>
{breadcrumbItems.map((item, index) => (
<React.Fragment key={index}>
<BreadcrumbSeparator />
<BreadcrumbItem>
{item.isLast ? (
<BreadcrumbPage>{item.label}</BreadcrumbPage>
) : (
<BreadcrumbLink asChild>
<Link href={item.href!}>{item.label}</Link>
</BreadcrumbLink>
)}
</BreadcrumbItem>
</React.Fragment>
))}
</BreadcrumbList>
</Breadcrumb>
)
}
Breadcrumb with Dropdown Menu
Combine with DropdownMenu for additional navigation options:
function BreadcrumbWithMenu() {
return (
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/">Home</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<DropdownMenu>
<DropdownMenuTrigger className="flex items-center gap-1">
Products
<ChevronDownIcon className="size-4" />
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuItem asChild>
<Link href="/products/electronics">Electronics</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/products/clothing">Clothing</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/products/books">Books</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>MacBook Pro</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
)
}
Accessibility
Screen Reader Support
Breadcrumbs provide rich semantic information:
- Navigation landmark: Announced as "breadcrumb navigation"
- Ordered structure: Screen readers understand the hierarchy
- Current location: Clearly identified with
aria-current="page"
Keyboard Navigation
Standard link navigation applies:
- Tab: Move between breadcrumb links
- Enter/Space: Activate links
- Arrow keys: Not used (standard link behavior)
ARIA Attributes
The component automatically handles:
// Automatically applied
<nav aria-label="breadcrumb">
<ol>
<li>
<a href="/home">Home</a>
</li>
<li role="presentation" aria-hidden="true">
<ChevronRightIcon />
</li>
<li>
<span role="link" aria-disabled="true" aria-current="page">
Current Page
</span>
</li>
</ol>
</nav>
SEO Benefits
Search Engine Optimization
Breadcrumbs improve SEO through:
- Internal Linking: Creates natural link hierarchy
- Context Signals: Helps search engines understand site structure
- Rich Snippets: May appear in search results
- User Experience: Reduces bounce rate with better navigation
Structured Data
Consider adding JSON-LD structured data:
function SEOBreadcrumb({ items }) {
const structuredData = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": items.map((item, index) => ({
"@type": "ListItem",
"position": index + 1,
"name": item.label,
"item": item.href ? `https://example.com${item.href}` : undefined
}))
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
/>
<Breadcrumb>
{/* Breadcrumb implementation */}
</Breadcrumb>
</>
)
}
Performance Considerations
Client-Side Navigation
Optimize for single-page applications:
// Use Next.js Link for client-side navigation
<BreadcrumbLink asChild>
<Link href="/products" prefetch={false}>
Products
</Link>
</BreadcrumbLink>
Dynamic Loading
For large site structures, consider lazy loading:
function LazyBreadcrumb({ path }) {
const [breadcrumbData, setBreadcrumbData] = useState(null)
useEffect(() => {
// Fetch breadcrumb data based on current path
fetchBreadcrumbData(path).then(setBreadcrumbData)
}, [path])
if (!breadcrumbData) {
return <BreadcrumbSkeleton />
}
return <Breadcrumb>{/* Render with data */}</Breadcrumb>
}
Troubleshooting
Common Issues
- Links not working: Ensure proper
asChild
usage with routing libraries - Separators not aligned: Check icon sizing and container spacing
- Responsive issues: Verify text wrapping and gap classes
- Accessibility warnings: Ensure current page uses
BreadcrumbPage
Debugging
// Add visual debugging
<BreadcrumbList className="border border-red-200 bg-red-50">
{/* Breadcrumb items */}
</BreadcrumbList>
// Log breadcrumb structure
console.log('Breadcrumb path:', pathname.split('/'))
Integration Examples
With App Router
// app/products/[category]/[id]/page.tsx
export default function ProductPage({ params }) {
return (
<div>
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/">Home</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/products">Products</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href={`/products/${params.category}`}>
{params.category}
</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>{params.id}</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>
)
}