Breadcrumbs
Overview
Breadcrumbs is a server-rendered navigation component that automatically builds a breadcrumb trail from the active WordPress query. Unlike interactive components (Accordion, Tabs, etc.), Breadcrumbs has no client-side runtime — the trail is resolved entirely in PHP during block rendering and injected into the page as final HTML.
The component automatically handles pages with parent/ancestor hierarchies, single posts with category ancestry, custom post type archives, term archives, date archives, author archives, search results, and 404 pages. It also outputs BreadcrumbList JSON-LD structured data for SEO when enabled.
Breadcrumbs is a single-component family — there are no sub-components. It is placed into patterns or templates and the server-side trail resolver does the rest.
Authoring Structure
Breadcrumbs (OmeBreadcrumbs)
├── Home slot (optional custom home content)
└── Separator slot (optional custom separator content)
Placement Rules
| Slot | Purpose |
|---|---|
| home | Custom content inside the home link. When empty, the homeLabel text is used. |
| separator | Custom separator between items. When empty, the separator text is used. |
How It Works
Breadcrumbs uses a two-phase rendering pipeline:
- Editor / Preview phase — The component renders a static preview with placeholder items ("Home", "Blog", "Current page") so the editor shows a representative breadcrumb trail.
- Frontend phase — A block interceptor (
BreadcrumbsBlockInterceptor) replaces the placeholder with a real breadcrumb trail resolved from the current WordPress query context viaBreadcrumbTrailResolver.
This means the breadcrumb trail is always accurate for the current page — no manual item configuration is needed.
Supported WordPress Contexts
| Context | Trail |
|---|---|
| Front page | Hidden by default (enable with showOnFrontPage). |
| Posts index | Home → Blog (or custom Posts Page). |
| Single post | Home → Blog → Category → Post. |
| Page (with ancestors) | Home → Parent → … → Page. |
| Custom post type | Home → Archive → Term (if hierarchical) → Post. |
| Post type archive | Home → Archive. |
| Term archive | Home → … → Term (with ancestor terms for hierarchical taxonomies). |
| Date archive | Home → Year → Month → Day (drills down as deep as the URL). |
| Author archive | Home → Author name. |
| Search results | Home → Search. |
| 404 | Home → Not Found. |
Quick Start
<OmeBreadcrumbs
content='{{"homeLabel":"Home","separator":"/","ariaLabel":"Breadcrumb"}}'
settings='{{"showHome":true,"showCurrent":true,"linkCurrent":false,"showOnFrontPage":false,"enableSchema":true}}'
/>
<OmeBreadcrumbs
content='{{"homeLabel":"Home","separator":"/","ariaLabel":"Breadcrumb"}}'
settings='{{"showHome":true,"showCurrent":true}}'
>
{#slot separator}
<span class="my-separator" aria-hidden="true">→</span>
{/slot}
</OmeBreadcrumbs>
<OmeBreadcrumbs
content='{{"homeLabel":"Home","separator":"/","ariaLabel":"Breadcrumb"}}'
settings='{{"showHome":true,"showCurrent":true}}'
>
{#slot home}
<svg class="home-icon" aria-hidden="true" width="16" height="16"><!-- icon SVG --></svg>
{/slot}
</OmeBreadcrumbs>
Props
Content Props
| Prop | Type | Default | Description |
|---|---|---|---|
homeLabel | string | Home | Text used for the home breadcrumb. Shown when the |
separator | string | / | Text shown between breadcrumb items. Shown when the |
ariaLabel | string | Breadcrumb | Accessible label for the |
Settings Props
| Prop | Type | Default | Description |
|---|---|---|---|
showHome | boolean | true | Includes the home breadcrumb as the first item in the trail. |
showCurrent | boolean | true | Includes the current page as the last item in the trail. When |
linkCurrent | boolean | false | Renders the current page breadcrumb as a link ( |
showOnFrontPage | boolean | false | Keeps breadcrumbs visible on the front page. When |
enableSchema | boolean | true | Outputs a |
Styling Props
| Prop | Type | Default | Description |
|---|---|---|---|
rootClass | class | ome-breadcrumbs-root-default | CSS class applied to the root |
listClass | class | ome-breadcrumbs-list-default | CSS class applied to the |
itemClass | class | ome-breadcrumbs-item-default | CSS class applied to each |
linkClass | class | ome-breadcrumbs-link-default | CSS class applied to each |
currentClass | class | ome-breadcrumbs-current-default | CSS class applied to the current page item (whether rendered as a link or span). |
separatorClass | class | ome-breadcrumbs-separator-default | CSS class applied to each separator |
Default CSS
The default styles provide a horizontal flex layout with ACSS-aware custom properties:
/* Root: inherits text color and uses small text size */
.ome-breadcrumbs-root-default {
color: var(--text-dark, currentColor);
font-size: var(--text-s, 0.875rem);
}
/* List: horizontal flexbox with wrapping */
.ome-breadcrumbs-list-default {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-xs, 0.75rem);
margin: 0;
padding: 0;
}
/* Items: inline flex, no list style */
.ome-breadcrumbs-item-default {
display: inline-flex;
align-items: center;
gap: var(--space-xs, 0.75rem);
list-style: none;
}
The fixed base styles enforce box-sizing: border-box, hide [hidden] elements, and provide :focus-visible outline styling on links — matching the same foundation used across all Etch components.
Accessibility
The rendered markup uses semantic HTML:
- The root element is a
<nav>witharia-label(defaults to "Breadcrumb"). - The list uses an ordered list
<ol>for correct semantics. - The current page item has
aria-current="page". - Separators are marked
aria-hidden="true"to avoid screen reader noise. :focus-visibleoutlines are provided by the fixed base styles.
Common Mistakes
Breadcrumbs is entirely server-rendered. There is no JavaScript runtime for this component — the trail is resolved in PHP during render_block. You cannot dynamically update breadcrumbs with client-side JavaScript.
By default showOnFrontPage is false, which means the component outputs nothing on the front page. If your design calls for breadcrumbs on the homepage, set showOnFrontPage to true and showHome to true.
If you use Yoast SEO, Rank Math, or another plugin that generates BreadcrumbList JSON-LD, set enableSchema to false to avoid duplicate schema output.
The editor renders static placeholder items ("Home", "Blog", "Current page") so you can preview the visual design. The actual breadcrumb trail is only generated on the frontend from the real WordPress query context.
FAQs
Can I customize which categories appear for single posts?
The trail resolver picks the first assigned term (lowest term_id) from the post's categories. To control which category appears, assign only one category to the post, or use a plugin that filters get_the_terms.
Does this work with custom post types?
Yes. For custom post types with has_archive, the resolver includes the post type archive link. If the post type has hierarchical taxonomies, the first assigned term in the first public hierarchical taxonomy is included in the trail.
Can I use a custom icon or SVG for the separator?
Yes. Use the separator slot to provide custom markup instead of the plain text separator:
<OmeBreadcrumbs>
{#slot separator}
<span aria-hidden="true">
<svg><!-- your icon --></svg>
</span>
{/slot}
</OmeBreadcrumbs>
What happens on pages with no ancestors?
For a top-level page, the trail is simply: Home → Page Title. For nested pages, each ancestor is included in order: Home → Parent → Grandparent → Page Title.
Why is the schema not appearing?
Schema output requires at least two items with URLs in the trail. If showHome is false and only the current page remains, or if the trail has fewer than two linkable items, the JSON-LD script tag is omitted. Also check that enableSchema is true.