UI Components Easy
Breadcrumb Nav
Accessible breadcrumb navigation with structured data, truncation for deep paths, and home icon. Pure CSS + minimal JS.
Open in Lab
MCP
css vanilla-js
Targets: JS HTML
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #0f1117;
--surface: #16181f;
--border: #2a2d3a;
--text: #e2e8f0;
--text-muted: #64748b;
--accent: #818cf8;
--accent-hover: #a5b4fc;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
padding: 40px 24px;
}
.demo-wrap {
max-width: 740px;
margin: 0 auto;
}
.demo-title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 36px;
}
.bc-section {
margin-bottom: 36px;
}
.bc-section-label {
font-size: 0.72rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .08em;
color: var(--text-muted);
margin-bottom: 12px;
}
/* ── Breadcrumb ── */
.breadcrumb {
}
.bc-list {
list-style: none;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0;
}
.bc-item {
display: flex;
align-items: center;
}
/* Separator */
.bc-item + .bc-item::before {
content: "";
display: inline-block;
width: 14px;
height: 14px;
background: currentColor;
color: var(--text-muted);
margin: 0 4px;
clip-path: polygon(30% 0%, 70% 50%, 30% 100%, 20% 90%, 55% 50%, 20% 10%);
opacity: 0.5;
}
.bc-link {
display: flex;
align-items: center;
gap: 4px;
color: var(--text-muted);
text-decoration: none;
font-size: 0.875rem;
font-weight: 500;
padding: 4px 6px;
border-radius: 6px;
transition: color .15s, background .15s;
}
.bc-link:hover {
color: var(--text);
background: rgba(255, 255, 255, 0.05);
}
.bc-link--home {
color: var(--accent);
}
.bc-link--home:hover {
color: var(--accent-hover);
background: rgba(129, 140, 248, 0.08);
}
.bc-current {
font-size: 0.875rem;
font-weight: 600;
color: var(--text);
padding: 4px 6px;
}
.bc-ellipsis {
background: var(--surface);
border: 1px solid var(--border);
color: var(--text-muted);
border-radius: 4px;
font-size: 0.9rem;
cursor: pointer;
padding: 0 8px 2px;
line-height: 1.5;
transition: background .15s, color .15s;
}
.bc-ellipsis:hover {
background: var(--border);
color: var(--text);
}
.bc-item--hidden {
display: none;
}
.bc-item--hidden.revealed {
display: flex;
}
.bc-item--collapsed.hidden {
display: none;
}
/* Pill variant */
.breadcrumb--pill .bc-list {
gap: 6px;
}
.breadcrumb--pill .bc-item + .bc-item::before {
display: none;
}
.breadcrumb--pill .bc-link,
.breadcrumb--pill .bc-current {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 999px;
padding: 3px 12px;
font-size: 0.8rem;
}
.breadcrumb--pill .bc-item--current .bc-current {
background: rgba(129, 140, 248, 0.12);
border-color: var(--accent);
color: var(--accent);
}// Ellipsis expand button
const ellipsisBtn = document.getElementById("bc-ellipsis-btn");
const collapsed = document.getElementById("bc-collapsed");
ellipsisBtn?.addEventListener("click", () => {
document.querySelectorAll(".bc-item--hidden").forEach((el) => el.classList.add("revealed"));
collapsed?.classList.add("hidden");
});
// JSON-LD BreadcrumbList structured data
function injectBreadcrumbSchema(navEl) {
const links = navEl.querySelectorAll("[data-href]");
const current = navEl.querySelector('[aria-current="page"]');
const items = [];
links.forEach((link, i) => {
items.push({
"@type": "ListItem",
position: i + 1,
name: link.textContent.trim() || "Home",
item: window.location.origin + link.dataset.href,
});
});
if (current) {
items.push({
"@type": "ListItem",
position: items.length + 1,
name: current.textContent.trim(),
});
}
const script = document.createElement("script");
script.type = "application/ld+json";
script.text = JSON.stringify({
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: items,
});
document.head.appendChild(script);
}
document.querySelectorAll('[aria-label="Breadcrumb"]').forEach(injectBreadcrumbSchema);<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Breadcrumb Nav</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="demo-wrap">
<h1 class="demo-title">Breadcrumb Nav</h1>
<!-- ── Breadcrumb 1: Short ── -->
<section class="bc-section">
<h2 class="bc-section-label">Short path</h2>
<nav aria-label="Breadcrumb" class="breadcrumb">
<ol class="bc-list" id="bc-short">
<li class="bc-item">
<a href="#" class="bc-link bc-link--home" data-href="/" aria-label="Home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2.5">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
</a>
</li>
<li class="bc-item">
<a href="#" class="bc-link" data-href="/library">Library</a>
</li>
<li class="bc-item bc-item--current" aria-current="page">
<span class="bc-current">Navigation Menu</span>
</li>
</ol>
</nav>
</section>
<!-- ── Breadcrumb 2: Long ── -->
<section class="bc-section">
<h2 class="bc-section-label">Deep path (with truncation)</h2>
<nav aria-label="Breadcrumb" class="breadcrumb">
<ol class="bc-list" id="bc-long">
<li class="bc-item">
<a href="#" class="bc-link bc-link--home" data-href="/" aria-label="Home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2.5">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
<polyline points="9 22 9 12 15 12 15 22" />
</svg>
</a>
</li>
<li class="bc-item">
<a href="#" class="bc-link" data-href="/dashboard">Dashboard</a>
</li>
<li class="bc-item bc-item--collapsed" id="bc-collapsed">
<button class="bc-ellipsis" aria-label="Show full path" id="bc-ellipsis-btn">…</button>
</li>
<li class="bc-item bc-item--hidden" id="bc-h1">
<a href="#" class="bc-link" data-href="/dashboard/settings">Settings</a>
</li>
<li class="bc-item bc-item--hidden" id="bc-h2">
<a href="#" class="bc-link" data-href="/dashboard/settings/security">Security</a>
</li>
<li class="bc-item">
<a href="#" class="bc-link" data-href="/dashboard/settings/security/two-factor">Two-Factor</a>
</li>
<li class="bc-item bc-item--current" aria-current="page">
<span class="bc-current">App Authenticator</span>
</li>
</ol>
</nav>
</section>
<!-- ── Breadcrumb 3: Pill style ── -->
<section class="bc-section">
<h2 class="bc-section-label">Pill / tag style</h2>
<nav aria-label="Breadcrumb" class="breadcrumb breadcrumb--pill">
<ol class="bc-list" id="bc-pill">
<li class="bc-item">
<a href="#" class="bc-link" data-href="/">Home</a>
</li>
<li class="bc-item">
<a href="#" class="bc-link" data-href="/products">Products</a>
</li>
<li class="bc-item bc-item--current" aria-current="page">
<span class="bc-current">Pro Plan</span>
</li>
</ol>
</nav>
</section>
</main>
<script src="script.js"></script>
</body>
</html>Breadcrumb Nav
An accessible breadcrumb navigation component with home icon, chevron separators, active state, and JSON-LD structured data injection for SEO.
Features
<nav aria-label="Breadcrumb">with<ol>list structure- Home icon for the root crumb
- SVG chevron separators via CSS
::after - Current page uses
aria-current="page"and distinct style - Truncates deeply nested paths with ellipsis crumb on narrow screens
- JS utility injects
application/ld+jsonBreadcrumbList structured data
How it works
- Breadcrumb items are
<li>elements inside an<ol>— separators provided by CSS::afterpseudo - The JS
generateSchema()function reads[data-href]attributes and injects aBreadcrumbList<script>tag - On mobile, a
ResizeObservercollapses middle crumbs into…to keep the trail readable