Table of Contents
- Introduction
- What We'll Build
- What is a Theme App Extension?
- Creating the Extension
- Building the Breadcrumb Markup
- Styling the Breadcrumbs
- Adding JSON-LD Structured Data
- Making It Configurable from the Theme Editor
- Complete File
- Things to Watch Out For
- Conclusion
- UR: Smart Breadcrumbs
- References
Introduction
Breadcrumb navigation is one of those small UI elements that punches well above its weight. For users, breadcrumbs provide a clear sense of location within a store and a quick way to jump back to parent categories. For search engines, breadcrumbs provide structured hierarchy signals that improve how your pages appear in search results — Google can display breadcrumb trails directly in SERPs when it detects proper markup.
Despite this, many Shopify themes either lack breadcrumbs entirely or offer limited, hard-coded implementations that merchants can't customize. Building breadcrumbs as a Theme App Extension solves this perfectly: merchants get a configurable breadcrumb block they can place anywhere in the theme editor, and your code stays completely isolated from the theme's source files.
In this tutorial, I'll walk you through building a fully customizable breadcrumb navigation app block for Shopify. We'll handle every major page type — products, collections, articles, blogs, and static pages — and output JSON-LD structured data so search engines can parse the breadcrumb trail. By the end, you'll have production-ready code that merchants can configure from the theme editor with zero coding.
What We'll Build
Here's the finished breadcrumb navigation on a product page:
Merchants configure the delimiter, colors, font size, and mobile visibility directly from the theme editor:
The breadcrumb block will:
- Automatically generate the correct breadcrumb trail for products, collections, articles, blogs, and pages
- Output JSON-LD structured data for SEO
- Let merchants customize the delimiter, font size, text color, link color, and home link text
- Support toggling visibility on mobile and desktop independently
- Work across all Online Store 2.0 themes
What is a Theme App Extension?
Theme App Extensions let Shopify app developers inject UI components — called app blocks — into a merchant's theme without touching the theme's source code.
Why this matters for breadcrumbs:
- No theme code editing — Merchants add the breadcrumb block via the theme editor, just like any native section or block.
- Theme-safe — Your code lives inside your app. Theme updates won't overwrite or break your breadcrumbs.
- Uninstall-clean — When the app is uninstalled, the breadcrumb block is automatically removed. No leftover Liquid snippets.
App blocks are built with Liquid, CSS, and JavaScript — the same stack used in Shopify themes. If you've customized a Shopify theme before, you already know the tools.
For more details, see the official Shopify documentation on Theme App Extensions.
Creating the Extension
Prerequisites
Make sure you have:
- A Shopify Partner account
- A development store
- Shopify CLI installed
- An existing Shopify app (or create one with
shopify app init)
Generate the Extension
Inside your app directory, run:
shopify app generate extension --template theme_app_extension --name smart-breadcrumbs
This creates the following structure:
extensions/
smart-breadcrumbs/
blocks/
assets/
locales/
snippets/
Directory Overview
| Directory | Purpose |
|---|---|
blocks/ |
Liquid files that become app blocks in the theme editor |
assets/ |
CSS and JavaScript files |
locales/ |
Translation files for multi-language support |
snippets/ |
Reusable Liquid snippets |
We'll create three files:
-
blocks/breadcrumbs.liquid— the main Liquid template with breadcrumb logic and schema -
assets/breadcrumbs.css— styles for the breadcrumb component
Let's start building.
Building the Breadcrumb Markup
Create the app block file at extensions/smart-breadcrumbs/blocks/breadcrumbs.liquid.
The core challenge with breadcrumbs on Shopify is that different page types require different breadcrumb structures. A product page might show Home > Collection > Product, while a blog article shows Home > Blog > Article. We need to detect the current page type using the template object and build the trail accordingly.
The Breadcrumb Container
First, let's set up the outer wrapper and the Home link, which is common to every page type:
{{ 'breadcrumbs.css' | asset_url | stylesheet_tag }}
{% assign delimiter = block.settings.delimiter %}
{% assign home_text = block.settings.home_text %}
<nav
class="app-breadcrumbs"
aria-label="Breadcrumb"
style="
--breadcrumb-font-size: {{ block.settings.font_size }}px;
--breadcrumb-text-color: {{ block.settings.text_color }};
--breadcrumb-link-color: {{ block.settings.link_color }};
--breadcrumb-delimiter-color: {{ block.settings.delimiter_color }};
{% if block.settings.show_on_mobile == false %}
--breadcrumb-mobile-display: none;
{% endif %}
{% if block.settings.show_on_desktop == false %}
--breadcrumb-desktop-display: none;
{% endif %}
"
>
<ol class="app-breadcrumbs__list">
<li class="app-breadcrumbs__item">
<a href="/" class="app-breadcrumbs__link">{{ home_text }}</a>
</li>
<!-- Page-type-specific crumbs will go here -->
</ol>
</nav>
We pass merchant settings as CSS custom properties through inline styles. This keeps the Liquid template clean and gives us a single place to consume settings in CSS. The aria-label="Breadcrumb" attribute tells screen readers this is a breadcrumb navigation landmark.
Handling Each Page Type
Now let's fill in the breadcrumb trail for each page type. We'll use Shopify's template.name and template.suffix to detect where we are.
Product Pages
Product pages are the most common breadcrumb use case. When a customer arrives at a product from a collection, Shopify makes the referring collection available through collection. If no collection context exists (e.g., the customer arrived via a direct link), we fall back to the product's first collection:
{% if template.name == 'product' %}
{% if collection %}
{% assign current_collection = collection %}
{% elsif product.collections.size > 0 %}
{% assign current_collection = product.collections[0] %}
{% endif %}
{% if current_collection %}
<li class="app-breadcrumbs__item">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<a href="{{ current_collection.url }}" class="app-breadcrumbs__link">
{{ current_collection.title }}
</a>
</li>
{% endif %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ product.title }}</span>
</li>
{% endif %}
A few things to note:
- The
collectionobject is automatically populated by Shopify when a customer navigates from a collection page to a product. This is why breadcrumbs on product pages can show the correct parent collection contextually. - We use
aria-current="page"on the last crumb to indicate the current page to assistive technologies. - The current page (last crumb) is rendered as a
<span>, not a link — linking to the current page is bad UX and bad for accessibility.
Collection Pages
Collection pages are straightforward — just Home > Collection Name:
{% if template.name == 'collection' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ collection.title }}</span>
</li>
{% endif %}
Blog Article Pages
Articles live under a blog, so the trail is Home > Blog > Article:
{% if template.name == 'article' %}
<li class="app-breadcrumbs__item">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<a href="{{ blog.url }}" class="app-breadcrumbs__link">
{{ blog.title }}
</a>
</li>
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ article.title }}</span>
</li>
{% endif %}
Blog Pages
When viewing the blog index (list of articles), the trail is just Home > Blog:
{% if template.name == 'blog' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ blog.title }}</span>
</li>
{% endif %}
Static Pages
Static pages (About Us, Contact, etc.) follow the same simple pattern:
{% if template.name == 'page' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ page.title }}</span>
</li>
{% endif %}
Search and Cart Pages
Search results and cart pages deserve breadcrumbs too:
{% if template.name == 'search' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">Search</span>
</li>
{% endif %}
{% if template.name == 'cart' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">Cart</span>
</li>
{% endif %}
Styling the Breadcrumbs
Create extensions/smart-breadcrumbs/assets/breadcrumbs.css:
.app-breadcrumbs {
padding: 12px 0;
font-size: var(--breadcrumb-font-size, 14px);
color: var(--breadcrumb-text-color, #666);
line-height: 1.5;
}
.app-breadcrumbs__list {
display: flex;
flex-wrap: wrap;
align-items: center;
list-style: none;
margin: 0;
padding: 0;
gap: 4px;
}
.app-breadcrumbs__item {
display: flex;
align-items: center;
gap: 4px;
}
.app-breadcrumbs__link {
color: var(--breadcrumb-link-color, #333);
text-decoration: none;
transition: opacity 0.2s ease;
}
.app-breadcrumbs__link:hover {
opacity: 0.7;
text-decoration: underline;
}
.app-breadcrumbs__delimiter {
color: var(--breadcrumb-delimiter-color, #999);
user-select: none;
}
.app-breadcrumbs__current {
color: var(--breadcrumb-text-color, #666);
}
/* Responsive visibility */
@media screen and (max-width: 749px) {
.app-breadcrumbs {
display: var(--breadcrumb-mobile-display, block);
}
}
@media screen and (min-width: 750px) {
.app-breadcrumbs {
display: var(--breadcrumb-desktop-display, block);
}
}
Key styling decisions:
-
Flexbox with
flex-wrap— breadcrumbs wrap gracefully on narrow screens instead of overflowing. - CSS custom properties — all colors and sizes come from the Liquid template's inline styles, which read from merchant settings. This means zero JavaScript is needed for customization.
-
Responsive visibility — the
--breadcrumb-mobile-displayand--breadcrumb-desktop-displayvariables control whether breadcrumbs appear on each device type. By default, they show on both. - Minimal footprint — no shadows, no borders, no heavy decoration. Breadcrumbs should blend into the store's existing design, not compete with it.
Adding JSON-LD Structured Data
Breadcrumbs are one of the most impactful structured data types you can add to a Shopify store. When Google detects valid breadcrumb markup, it can replace the raw URL in search results with a formatted breadcrumb trail — making your listings more readable and clickable.
We'll output JSON-LD structured data alongside the visible breadcrumbs. JSON-LD is Google's preferred format for structured data, and it's cleanly separated from the HTML markup.
Add this right after the closing </nav> tag in breadcrumbs.liquid:
{% comment %} JSON-LD Structured Data {% endcomment %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": {{ home_text | json }},
"item": "{{ shop.url }}"
}
{% if template.name == 'product' %}
{% if current_collection %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ current_collection.title | json }},
"item": "{{ shop.url }}{{ current_collection.url }}"
}
,{
"@type": "ListItem",
"position": 3,
"name": {{ product.title | json }}
}
{% else %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ product.title | json }}
}
{% endif %}
{% endif %}
{% if template.name == 'collection' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ collection.title | json }}
}
{% endif %}
{% if template.name == 'article' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ blog.title | json }},
"item": "{{ shop.url }}{{ blog.url }}"
}
,{
"@type": "ListItem",
"position": 3,
"name": {{ article.title | json }}
}
{% endif %}
{% if template.name == 'blog' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ blog.title | json }}
}
{% endif %}
{% if template.name == 'page' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ page.title | json }}
}
{% endif %}
]
}
</script>
A few important details:
-
The last item has no
itemproperty — per Google's structured data guidelines, the last breadcrumb (the current page) should omit theitemURL. -
We use the
| jsonLiquid filter to safely escape product and collection titles. This prevents broken JSON when titles contain quotes, ampersands, or other special characters. -
shop.urlprovides the full domain — Shopify'scollection.urlandblog.urlreturn relative paths (e.g.,/collections/shoes), so we prependshop.urlto create fully qualified URLs that search engines expect.
You can validate your structured data using Google's Rich Results Test after deploying.
Making It Configurable from the Theme Editor
Now let's add the {% schema %} block that defines how merchants interact with the breadcrumb settings in the theme editor. This goes at the bottom of breadcrumbs.liquid:
{% schema %}
{
"name": "Breadcrumbs",
"target": "section",
"settings": [
{
"type": "text",
"id": "home_text",
"label": "Home link text",
"default": "Home"
},
{
"type": "text",
"id": "delimiter",
"label": "Delimiter",
"default": "/"
},
{
"type": "range",
"id": "font_size",
"label": "Font size",
"min": 10,
"max": 24,
"step": 1,
"default": 14,
"unit": "px"
},
{
"type": "color",
"id": "text_color",
"label": "Current page text color",
"default": "#666666"
},
{
"type": "color",
"id": "link_color",
"label": "Link color",
"default": "#333333"
},
{
"type": "color",
"id": "delimiter_color",
"label": "Delimiter color",
"default": "#999999"
},
{
"type": "checkbox",
"id": "show_on_mobile",
"label": "Show on mobile",
"default": true
},
{
"type": "checkbox",
"id": "show_on_desktop",
"label": "Show on desktop",
"default": true
}
]
}
{% endschema %}
This schema gives merchants full control over:
- Home link text — Some stores prefer "Top" or "Store" instead of "Home"
-
Delimiter — Choose between
/,>,›,→, or any custom character - Font size — A range slider from 10px to 24px
- Colors — Independent control over link color, current page text color, and delimiter color
- Responsive visibility — Toggle breadcrumbs on/off for mobile and desktop independently
The "target": "section" property tells Shopify this block can be added to any section in the theme editor — merchants simply click "Add block" and search for "Breadcrumbs."
Complete File
Here's the entire extensions/smart-breadcrumbs/blocks/breadcrumbs.liquid file in one piece. You can copy this directly into your project:
{{ 'breadcrumbs.css' | asset_url | stylesheet_tag }}
{% assign delimiter = block.settings.delimiter %}
{% assign home_text = block.settings.home_text %}
{% comment %} Determine collection context for product pages {% endcomment %}
{% if template.name == 'product' %}
{% if collection %}
{% assign current_collection = collection %}
{% elsif product.collections.size > 0 %}
{% assign current_collection = product.collections[0] %}
{% endif %}
{% endif %}
<nav
class="app-breadcrumbs"
aria-label="Breadcrumb"
style="
--breadcrumb-font-size: {{ block.settings.font_size }}px;
--breadcrumb-text-color: {{ block.settings.text_color }};
--breadcrumb-link-color: {{ block.settings.link_color }};
--breadcrumb-delimiter-color: {{ block.settings.delimiter_color }};
{% if block.settings.show_on_mobile == false %}
--breadcrumb-mobile-display: none;
{% endif %}
{% if block.settings.show_on_desktop == false %}
--breadcrumb-desktop-display: none;
{% endif %}
"
>
<ol class="app-breadcrumbs__list">
{%- comment -%} Home link (always present) {%- endcomment -%}
<li class="app-breadcrumbs__item">
<a href="/" class="app-breadcrumbs__link">{{ home_text }}</a>
</li>
{%- comment -%} Product pages: Home > Collection > Product {%- endcomment -%}
{% if template.name == 'product' %}
{% if current_collection %}
<li class="app-breadcrumbs__item">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<a href="{{ current_collection.url }}" class="app-breadcrumbs__link">
{{ current_collection.title }}
</a>
</li>
{% endif %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ product.title }}</span>
</li>
{% endif %}
{%- comment -%} Collection pages: Home > Collection {%- endcomment -%}
{% if template.name == 'collection' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ collection.title }}</span>
</li>
{% endif %}
{%- comment -%} Article pages: Home > Blog > Article {%- endcomment -%}
{% if template.name == 'article' %}
<li class="app-breadcrumbs__item">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<a href="{{ blog.url }}" class="app-breadcrumbs__link">
{{ blog.title }}
</a>
</li>
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ article.title }}</span>
</li>
{% endif %}
{%- comment -%} Blog pages: Home > Blog {%- endcomment -%}
{% if template.name == 'blog' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ blog.title }}</span>
</li>
{% endif %}
{%- comment -%} Static pages: Home > Page {%- endcomment -%}
{% if template.name == 'page' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">{{ page.title }}</span>
</li>
{% endif %}
{%- comment -%} Search page: Home > Search {%- endcomment -%}
{% if template.name == 'search' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">Search</span>
</li>
{% endif %}
{%- comment -%} Cart page: Home > Cart {%- endcomment -%}
{% if template.name == 'cart' %}
<li class="app-breadcrumbs__item app-breadcrumbs__item--current" aria-current="page">
<span class="app-breadcrumbs__delimiter">{{ delimiter }}</span>
<span class="app-breadcrumbs__current">Cart</span>
</li>
{% endif %}
</ol>
</nav>
{% comment %} JSON-LD Structured Data {% endcomment %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": {{ home_text | json }},
"item": "{{ shop.url }}"
}
{% if template.name == 'product' %}
{% if current_collection %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ current_collection.title | json }},
"item": "{{ shop.url }}{{ current_collection.url }}"
}
,{
"@type": "ListItem",
"position": 3,
"name": {{ product.title | json }}
}
{% else %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ product.title | json }}
}
{% endif %}
{% endif %}
{% if template.name == 'collection' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ collection.title | json }}
}
{% endif %}
{% if template.name == 'article' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ blog.title | json }},
"item": "{{ shop.url }}{{ blog.url }}"
}
,{
"@type": "ListItem",
"position": 3,
"name": {{ article.title | json }}
}
{% endif %}
{% if template.name == 'blog' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ blog.title | json }}
}
{% endif %}
{% if template.name == 'page' %}
,{
"@type": "ListItem",
"position": 2,
"name": {{ page.title | json }}
}
{% endif %}
]
}
</script>
{% schema %}
{
"name": "Breadcrumbs",
"target": "section",
"settings": [
{
"type": "text",
"id": "home_text",
"label": "Home link text",
"default": "Home"
},
{
"type": "text",
"id": "delimiter",
"label": "Delimiter",
"default": "/"
},
{
"type": "range",
"id": "font_size",
"label": "Font size",
"min": 10,
"max": 24,
"step": 1,
"default": 14,
"unit": "px"
},
{
"type": "color",
"id": "text_color",
"label": "Current page text color",
"default": "#666666"
},
{
"type": "color",
"id": "link_color",
"label": "Link color",
"default": "#333333"
},
{
"type": "color",
"id": "delimiter_color",
"label": "Delimiter color",
"default": "#999999"
},
{
"type": "checkbox",
"id": "show_on_mobile",
"label": "Show on mobile",
"default": true
},
{
"type": "checkbox",
"id": "show_on_desktop",
"label": "Show on desktop",
"default": true
}
]
}
{% endschema %}
And here's the complete extensions/smart-breadcrumbs/assets/breadcrumbs.css:
.app-breadcrumbs {
padding: 12px 0;
font-size: var(--breadcrumb-font-size, 14px);
color: var(--breadcrumb-text-color, #666);
line-height: 1.5;
}
.app-breadcrumbs__list {
display: flex;
flex-wrap: wrap;
align-items: center;
list-style: none;
margin: 0;
padding: 0;
gap: 4px;
}
.app-breadcrumbs__item {
display: flex;
align-items: center;
gap: 4px;
}
.app-breadcrumbs__link {
color: var(--breadcrumb-link-color, #333);
text-decoration: none;
transition: opacity 0.2s ease;
}
.app-breadcrumbs__link:hover {
opacity: 0.7;
text-decoration: underline;
}
.app-breadcrumbs__delimiter {
color: var(--breadcrumb-delimiter-color, #999);
user-select: none;
}
.app-breadcrumbs__current {
color: var(--breadcrumb-text-color, #666);
}
/* Responsive visibility */
@media screen and (max-width: 749px) {
.app-breadcrumbs {
display: var(--breadcrumb-mobile-display, block);
}
}
@media screen and (min-width: 750px) {
.app-breadcrumbs {
display: var(--breadcrumb-desktop-display, block);
}
}
Things to Watch Out For
Collection Context on Product Pages
The collection Liquid object is only available when a customer navigates to a product from a collection page. If someone lands on a product via a direct link, search, or a product recommendation, collection will be nil. Our code handles this by falling back to product.collections[0], but be aware that the breadcrumb trail might show a different collection than the one the customer expects if the product belongs to multiple collections.
Delimiter Characters and Encoding
Common delimiter choices include /, >, › (single right-pointing angle quotation mark), and →. All of these work fine in both the visible breadcrumbs and JSON-LD. However, if a merchant enters an HTML entity like >, Liquid will output it as the literal string > inside the JSON-LD <script> tag, which is technically valid but messy. Stick to actual characters rather than HTML entities.
JSON-LD Validation
Always test your structured data output with Google's Rich Results Test after deploying. Common issues include:
-
Missing
itemproperty on intermediate breadcrumbs — every breadcrumb except the last one needs a URL -
Relative URLs — Google expects fully qualified URLs, which is why we prepend
shop.url -
Special characters in titles — the
| jsonfilter handles this, but double-check with products that have quotes or ampersands in their names
Theme Editor Placement
Merchants should place the breadcrumb block at the top of the page template, typically inside the first section. Since the block uses "target": "section", it can be added to any section — but placement at the top of the main content area is the standard convention for breadcrumbs.
Performance
This implementation requires zero JavaScript — everything is handled by Liquid and CSS. The only assets loaded are a single small CSS file. This means breadcrumbs add virtually no overhead to page load time, which is important for Shopify stores where every millisecond of load time affects conversion rates.
Conclusion
We've built a production-ready breadcrumb navigation block that handles every major Shopify page type, outputs SEO-friendly JSON-LD structured data, and gives merchants full visual control from the theme editor — all without a single line of JavaScript.
The key takeaways:
- Theme App Extensions are the cleanest way to deliver UI components to Shopify merchants — no theme code editing, no ScriptTags, no leftovers on uninstall
- JSON-LD structured data for breadcrumbs can directly improve how your store appears in Google search results
- CSS custom properties are a powerful pattern for passing Liquid settings to stylesheets without JavaScript
-
Semantic HTML (
<nav>,<ol>,aria-label,aria-current) makes breadcrumbs accessible to all users
If you want breadcrumb functionality without building it yourself, check out UR: Smart Breadcrumbs — a no-code solution from UnReact that covers all of this and more.
UR: Smart Breadcrumbs
If you'd rather skip the implementation and add breadcrumbs to your store right away, UR: Smart Breadcrumbs by UnReact is a no-code Shopify app that delivers everything covered in this tutorial — and then some.
Key features:
- No-code setup — add breadcrumbs to any Online Store 2.0 theme with one click from the theme editor
- Customizable delimiters — choose from common separators or set your own custom character
- Full color and typography control — adjust font size, link color, text color, and delimiter color to match your store's design
- Responsive visibility toggles — show or hide breadcrumbs independently on mobile and desktop
- Home link customization — change the home link text and positioning to fit your store's navigation style
- Multi-language support — supports 20+ languages including English, Japanese, French, German, Spanish, and more
It's available on the Shopify App Store with a 7-day free trial.


Top comments (0)