Responsive Breadcrumb Navigation with HTML, CSS & JavaScript
• Updated 7/1/2026 • HTMLCSSJavaScriptResponsive DesignBreadcrumbsAccessibility
One-file front-end editor
Write plain HTML, CSS, JavaScript, or CDN-powered Vue and React demos.
Use Case
This snippet helps you build a responsive breadcrumb navigation component that does more than show page hierarchy. When a user clicks a breadcrumb link, the preview area updates with a matching Unsplash image, a title, and a short description.
This pattern is useful for interactive documentation demos, onboarding pages, category previews, learning platforms, portfolio sections, and UI component showcases where you want breadcrumbs to visually explain the current section.
- Shows the current path in a familiar breadcrumb layout.
- Uses semantic HTML and accessible navigation markup.
- Updates preview content without reloading the page.
- Uses Unsplash image URLs stored in HTML data attributes.
- Works well as a small real-world UI demo for beginner developers.
Concept Overview
A breadcrumb usually shows a path such as Home / Products / Electronics / Cameras. In a standard production page, the last breadcrumb item represents the current page. In this interactive demo, each breadcrumb item also acts like a content switcher that updates a preview card.
The HTML uses a nav element with aria-label="Breadcrumb" and an ordered list for the path. Each link includes custom data-* attributes such as data-image, data-title, and data-description. JavaScript reads those values when the user clicks a breadcrumb link and updates the preview section.
CSS handles the visual layout, spacing, hover states, current state, and responsive behavior. On smaller screens, the breadcrumb can scroll horizontally, while the preview layout stacks into a single column.
Complete Snippet Code
<div class="breadcrumb-demo">
<nav class="breadcrumb" aria-label="Breadcrumb">
<ol class="breadcrumb__list">
<li class="breadcrumb__item">
<a
class="breadcrumb__link is-current"
href="/"
aria-current="page"
data-title="Home"
data-description="Welcome to the main page. This preview uses an Unsplash image related to a clean developer workspace."
data-image="https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&w=1400&q=80"
data-alt="Laptop with code on the screen"
>
Home
</a>
</li>
<li class="breadcrumb__item">
<a
class="breadcrumb__link"
href="/products"
data-title="Products"
data-description="This section shows your main product or content categories. The preview updates when this breadcrumb is selected."
data-image="https://images.unsplash.com/photo-1518770660439-4636190af475?auto=format&fit=crop&w=1400&q=80"
data-alt="Close-up of electronic hardware on a desk"
>
Products
</a>
</li>
<li class="breadcrumb__item">
<a
class="breadcrumb__link"
href="/products/electronics"
data-title="Electronics"
data-description="This breadcrumb can represent a category page. The demo swaps in a matching Unsplash image."
data-image="https://images.unsplash.com/photo-1516035069371-29a1b244cc32?auto=format&fit=crop&w=1400&q=80"
data-alt="Photography and electronics setup"
>
Electronics
</a>
</li>
<li class="breadcrumb__item">
<a
class="breadcrumb__link"
href="/products/electronics/cameras"
data-title="Cameras"
data-description="This is the current page in the demo. Clicking breadcrumb items changes the active state and the preview image."
data-image="https://images.unsplash.com/photo-1502920917128-1aa500764cbd?auto=format&fit=crop&w=1400&q=80"
data-alt="Camera on a wooden surface"
>
Cameras
</a>
</li>
</ol>
</nav>
<section class="breadcrumb-preview" aria-live="polite">
<div class="breadcrumb-preview__media">
<img
id="breadcrumbPreviewImage"
src="https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&w=1400&q=80"
alt="Laptop with code on the screen"
/>
</div>
<div class="breadcrumb-preview__content">
<p class="breadcrumb-preview__eyebrow">Selected breadcrumb</p>
<h2 id="breadcrumbPreviewTitle">Home</h2>
<p id="breadcrumbPreviewDescription">
Welcome to the main page. This preview uses an Unsplash image related to a clean developer workspace.
</p>
</div>
</section>
</div>
<style>
.breadcrumb-demo {
--breadcrumb-link-color: #2563eb;
--breadcrumb-link-hover: #1d4ed8;
--breadcrumb-text-color: #4b5563;
--breadcrumb-muted-color: #9ca3af;
--breadcrumb-bg-color: #f9fafb;
--breadcrumb-border-color: #e5e7eb;
--breadcrumb-card-bg: #ffffff;
--breadcrumb-shadow: 0 10px 30px rgba(15, 23, 42, 0.08);
width: min(100%, 960px);
margin: 1.5rem auto;
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: #111827;
}
.breadcrumb {
margin-bottom: 1rem;
font-size: 0.95rem;
}
.breadcrumb__list {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0;
list-style: none;
margin: 0;
padding: 0.75rem 1rem;
border: 1px solid var(--breadcrumb-border-color);
border-radius: 0.75rem;
background: var(--breadcrumb-bg-color);
}
.breadcrumb__item {
display: inline-flex;
align-items: center;
min-width: 0;
line-height: 1.5;
}
.breadcrumb__item + .breadcrumb__item::before {
content: "/";
margin: 0 0.6rem;
color: var(--breadcrumb-muted-color);
}
.breadcrumb__link {
color: var(--breadcrumb-link-color);
text-decoration: none;
text-underline-offset: 0.2em;
border-radius: 0.4rem;
transition: color 0.2s ease, background-color 0.2s ease;
}
.breadcrumb__link:hover,
.breadcrumb__link:focus-visible {
color: var(--breadcrumb-link-hover);
text-decoration: underline;
}
.breadcrumb__link:focus-visible {
outline: 3px solid rgba(37, 99, 235, 0.25);
outline-offset: 3px;
}
.breadcrumb__link.is-current {
color: var(--breadcrumb-text-color);
font-weight: 700;
text-decoration: none;
pointer-events: none;
}
.breadcrumb-preview {
display: grid;
grid-template-columns: 1.2fr 1fr;
gap: 1.25rem;
align-items: stretch;
padding: 1rem;
border: 1px solid var(--breadcrumb-border-color);
border-radius: 1rem;
background: var(--breadcrumb-card-bg);
box-shadow: var(--breadcrumb-shadow);
}
.breadcrumb-preview__media {
overflow: hidden;
border-radius: 0.85rem;
min-height: 280px;
background: #e5e7eb;
}
.breadcrumb-preview__media img {
display: block;
width: 100%;
height: 100%;
min-height: 280px;
object-fit: cover;
}
.breadcrumb-preview__content {
display: flex;
flex-direction: column;
justify-content: center;
padding: 0.5rem 0.25rem;
}
.breadcrumb-preview__eyebrow {
margin: 0 0 0.5rem;
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--breadcrumb-link-color);
}
.breadcrumb-preview__content h2 {
margin: 0 0 0.75rem;
font-size: clamp(1.4rem, 2vw, 2rem);
line-height: 1.2;
}
.breadcrumb-preview__content p:last-child {
margin: 0;
color: var(--breadcrumb-text-color);
line-height: 1.7;
}
@media (max-width: 700px) {
.breadcrumb {
font-size: 0.9rem;
}
.breadcrumb__list {
flex-wrap: nowrap;
overflow-x: auto;
padding: 0.7rem 0.85rem;
scrollbar-width: thin;
}
.breadcrumb-preview {
grid-template-columns: 1fr;
}
.breadcrumb-preview__media,
.breadcrumb-preview__media img {
min-height: 220px;
}
}
</style>
<script>
const breadcrumbLinks = document.querySelectorAll(".breadcrumb__link");
const previewImage = document.getElementById("breadcrumbPreviewImage");
const previewTitle = document.getElementById("breadcrumbPreviewTitle");
const previewDescription = document.getElementById("breadcrumbPreviewDescription");
breadcrumbLinks.forEach((link) => {
link.addEventListener("click", (event) => {
event.preventDefault();
breadcrumbLinks.forEach((item) => {
item.classList.remove("is-current");
item.removeAttribute("aria-current");
});
link.classList.add("is-current");
link.setAttribute("aria-current", "page");
previewImage.src = link.dataset.image;
previewImage.alt = link.dataset.alt;
previewTitle.textContent = link.dataset.title;
previewDescription.textContent = link.dataset.description;
});
});
</script>
How It Works
- The breadcrumb structure uses
nav,ol, andlifor semantic meaning. - Each breadcrumb link stores preview data inside
data-title,data-description,data-image, anddata-alt. - When a link is clicked, JavaScript prevents the normal page jump for demo purposes.
- The script removes the active state from all breadcrumb links, then applies it to the clicked link.
- The preview image, heading, and description update from the selected link’s data attributes.
- The preview section uses
aria-live="polite"so assistive technologies can announce meaningful updates more gently. - CSS Grid handles the preview layout, while Flexbox keeps the breadcrumb path aligned and easy to scan.
- On narrow screens, the preview stacks vertically and the breadcrumb remains usable with horizontal scrolling.
How to Use This Snippet
- Copy the HTML, CSS, and JavaScript into your project.
- Replace the breadcrumb labels and
hrefvalues with your own page structure. - Update each
data-imagevalue with a relevant Unsplash image URL. - Write meaningful
data-alttext for every image so the preview remains accessible. - Change the default preview content so it matches the breadcrumb item you want selected on page load.
- In a real production breadcrumb, keep
aria-current="page"only on the actual current page.
Real Project Example
Imagine a learning platform that previews content sections before the user opens them. Each breadcrumb item can update a topic image and short explanation.
<li class="breadcrumb__item">
<a
class="breadcrumb__link"
href="/courses/frontend/css-grid"
data-title="CSS Grid"
data-description="Learn how to build two-dimensional layouts with rows, columns, and responsive grid areas."
data-image="https://images.unsplash.com/photo-1522542550221-31fd19575a2d?auto=format&fit=crop&w=1400&q=80"
data-alt="Developer working on a frontend layout"
>
CSS Grid
</a>
</li>
This turns a simple breadcrumb into a richer preview-driven navigation pattern that still feels familiar to users.
Customization Notes
- Change colors: Edit the CSS variables inside
.breadcrumb-demosuch as--breadcrumb-link-colorand--breadcrumb-bg-color. - Change the separator: Replace
content: "/";with another symbol such as"›","→", or"•". - Swap image sources: Replace Unsplash URLs with your own CDN, CMS, or local images if needed.
- Preselect another item: Move the
is-currentclass andaria-current="page"attribute to a different breadcrumb link and update the default preview values. - Add fade effects: You can add a small opacity transition to the preview image for a smoother visual change.
- Keep navigation real: Remove
event.preventDefault()if you want the links to navigate normally instead of acting as a demo switcher.
Common Mistakes
- Using missing image metadata: If a link has no
data-imageordata-alt, the preview can break or become less accessible. - Forgetting accessible alt text: Every preview image should describe the image meaningfully, not just repeat the section name.
- Treating demo behavior like production behavior: In a real page breadcrumb, only the current page should use
aria-current="page". - Making the layout too rigid: Test long breadcrumb labels and tall images so the component still looks good on smaller screens.
- Hardcoding only one preview: The point of this pattern is reusability, so keep content inside data attributes or structured data objects.
- Ignoring mobile testing: Make sure the breadcrumb remains easy to tap and the preview image scales without distortion.
Related Practice Ideas
- Create a version that loads breadcrumb data from a JavaScript array instead of inline data attributes.
- Build a product-category preview component for an ecommerce homepage.
- Turn this into a reusable React, Vue, Alpine, or Laravel Blade component.
- Add a fade animation or skeleton loading state for slower image connections.
- Store the selected breadcrumb in the URL hash so the preview can be linked directly.
- Create a CMS-driven version where editors can manage breadcrumb labels, images, and descriptions.
Support
Keep CompileQuestHub free
If this snippet helped you, support more open tutorials and code examples.
Need More?
Request a topic or report an issue
Use the contact form to request follow-up tutorials or report broken code, missing files, or outdated links.
Page Info
Freshness and topics
Topic: Breadcrumb Navigation
Difficulty: Beginner
Reading time: 6 min read
Published: 6/27/2026
Updated: 7/1/2026
Before You Start
Prerequisites
- Basic HTML knowledge
- Basic CSS knowledge
- Basic JavaScript knowledge
Outcome
What you will learn
- Create a responsive breadcrumb navigation component
- Implement accessible breadcrumb markup with ARIA attributes
- Use data attributes to store dynamic preview content
- Update an image preview with JavaScript when a breadcrumb link is clicked
- Adapt the layout for mobile screens using modern CSS
Learning Path
Accessible UI Components
Continue this sequence from the series page and move through the lessons in order.
Open seriesRelated
Keep going with nearby resources
Accessible Toast Notification Component with HTML, CSS, and JavaScript
Build a lightweight, reusable, screen-reader-friendly toast notification component with plain HTML, CSS, and JavaScript. Includes auto-dismiss, manual close, toast types, and practical customization options.
Responsive Image Gallery with CSS Grid and JavaScript Lightbox
Build a responsive image gallery using CSS Grid and a lightweight vanilla JavaScript lightbox with keyboard navigation, captions, and mobile-friendly styling.
Accessible Modal Dialog with HTML, CSS, and Vanilla JavaScript
Build a reusable, accessible modal dialog with semantic HTML, modern CSS, and vanilla JavaScript, including ARIA attributes, focus trapping, Escape key support, and restored focus.
Next Step

