Component Contract
Breadcrumb
Show a hierarchical page trail so users can navigate back through the site structure.
Live Demo
Breadcrumb
One pattern only: chevron separators (built into .caat-breadcrumb — no modifier, no inline style). The trail mirrors the content tree Home → current page; the IA stops at L4, so no deep-page truncation pattern exists.
Rendered
Item Length Cap (30 characters)
Each item has a 30-character visual cap — longer labels truncate with an ellipsis via CSS max-width: 30ch. The full label stays in the DOM and is also exposed via title.
Rendered
States
Ancestor-link interaction states. Hover and focus are shown statically via is-* classes mirroring the live :hover / :focus-visible rules; the current page uses .active (non-linked).
Rendered
1. Summary
| Component | Breadcrumb |
| Replaces | Breadcrumb (#1) |
| AEM Triage | Rebuild |
| Purpose | Show a hierarchical page trail so users can navigate back through the site structure. Helps users understand where they are within the CAAT website and quickly return to parent pages. |
| Core Interaction | Click any ancestor link to navigate up the hierarchy. The current page is displayed as non-linked text at the end of the trail. |
| Variants | None — a single pattern with chevron separators. (Slash and deep-page truncated variants removed by decision; the IA stops at L4 so deep trails cannot occur.) |
| Placement rule | Required on every Level 2+ page (see the Navigation Model). L1 pages and the homepage never show a breadcrumb. The trail mirrors the content tree from Home to the current page — including L4 pages, which the mega nav deliberately omits. |
2. Design Tokens
The breadcrumb clientlib consumes these semantic tokens — no component-specific tokens are defined.
| Token | Role |
|---|---|
--caat-color-text-link | Ancestor link colour |
--caat-color-text-link-hover | Link hover colour |
--caat-color-text-muted | Current-page text and separator colour |
--caat-blue-700 | Eyebrow / accent (where used) |
--caat-font-primary | Trail font family |
3. Authoring Fields
By default the breadcrumb is auto-generated from the AEM page hierarchy. Authors may optionally override with a manual multifield to customise labels and URLs.
| Field | Type | Required | Notes |
|---|---|---|---|
| Source | Radio group | Yes | Auto-generate from page tree (default) or Manual override |
| Start Level | Number | Yes | Depth level at which the trail begins (default: 2, i.e. below the site root) |
| Manual Items (multifield) | Multifield | No | Only visible when Source = Manual override |
| ↳ Label | Text | Yes | Displayed link text |
| ↳ URL | Pathfield | Yes | Internal page path or external URL |
4. Validation Rules
| Rule | Severity | Details |
|---|---|---|
| At least one ancestor link | Error | Breadcrumb must contain at least a Home link before the current page. |
| Manual items: label required | Error | Every manual multifield entry must have a non-empty label. |
| Manual items: URL required | Error | Every manual item (except the last) must have a valid URL. |
| Start level ≥ 1 | Error | Start level must be a positive integer. |
| Item length: 30-character visual cap | Warning | Labels longer than 30 characters remain in the HTML but visually truncate with an ellipsis via CSS max-width: 30ch; the full label is kept in title. Prefer concise navigation titles rather than relying on truncation. |
| Depth follows the IA | Error | The trail mirrors the content tree, which stops at L4 (max 5 items incl. Home) — no truncation pattern exists or is needed. |
| Present on L2+ pages | Error | Template policy: every Level 2, 3, and 4 page renders a breadcrumb; L1/home templates do not include the component. |
5. Content Guidance
| Guideline | Details |
|---|---|
| Labels | Use concise page titles (2–4 words). Avoid repeating the site name. E.g. "Pension Solutions" not "CAAT Pension Solutions Page". |
| Home link | Always start with "Home" as the first item linking to the site root. |
| Current page | Display as plain text (non-linked) and mark with aria-current="page". |
| Label length | Keep navigation titles short; anything past 30 characters is cut with an ellipsis. Prefer a shorter navigation title over relying on truncation. |
| Consistency | Breadcrumb labels should match the <title> or jcr:title of the target page. |
6. Semantic HTML
<!-- Standard breadcrumb -->
<nav aria-label="Breadcrumb" class="caat-breadcrumb"
data-analytics-component="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="/en.html"
data-analytics-label="breadcrumb-click"
data-analytics-level="1"
data-analytics-destination="home">Home</a>
</li>
<li class="breadcrumb-item">
<a href="/en/employers.html"
data-analytics-label="breadcrumb-click"
data-analytics-level="2"
data-analytics-destination="employers">Employers</a>
</li>
<li class="breadcrumb-item">
<a href="/en/employers/pension-solutions.html"
data-analytics-label="breadcrumb-click"
data-analytics-level="3"
data-analytics-destination="pension-solutions">Pension Solutions</a>
</li>
<li class="breadcrumb-item active" aria-current="page">Contact</li>
</ol>
</nav>
7. CSS Contract
| Selector | Purpose |
|---|---|
.caat-breadcrumb | Wrapper <nav> — sets font-size, padding, and token-based colours. |
.breadcrumb | Bootstrap's <ol> — inherits divider style and flex layout. |
.breadcrumb-item | Individual trail item. Applies link colour tokens and hover/focus states. |
.breadcrumb-item.active | Current page item — non-linked, muted colour. |
--bs-breadcrumb-divider | Set to the chevron SVG on .caat-breadcrumb — the separator is baked in; no modifier or inline style. |
/* breadcrumb.css — key rules */
.caat-breadcrumb {
font-size: var(--caat-breadcrumb-font-size, 0.875rem);
padding: var(--caat-breadcrumb-py, 0.75rem) 0;
}
.caat-breadcrumb .breadcrumb-item a {
color: var(--caat-breadcrumb-link-color);
text-decoration: none;
}
.caat-breadcrumb .breadcrumb-item a:hover {
color: var(--caat-breadcrumb-link-hover);
text-decoration: underline;
}
.caat-breadcrumb .breadcrumb-item.active {
color: var(--caat-breadcrumb-current-color);
}
/* 30-character item cap */
.caat-breadcrumb .breadcrumb-item a,
.caat-breadcrumb .breadcrumb-item.active {
display: inline-block;
max-width: 30ch;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
8. Accessibility
| Requirement | Implementation |
|---|---|
| Landmark | Wrap in <nav aria-label="Breadcrumb"> to expose a navigation landmark to assistive technologies. |
| Ordered list | Use <ol> so screen readers announce the number of items and their position. |
| Current page | Add aria-current="page" to the last <li> — the current page must not be a link. |
| Truncated labels | Items visually capped at 30 characters keep the full label as the text node and in the title attribute; do not server-truncate the accessible name. |
| Colour contrast | Link text must meet WCAG 2.1 AA — minimum 4.5 : 1 contrast against background. |
| Focus indicators | All links must show a visible focus ring meeting 3 : 1 contrast. |
| Structured data | Include JSON-LD BreadcrumbList schema (see Section 9) so assistive tools and search engines can parse the hierarchy. |
9. SEO
Emit a JSON-LD BreadcrumbList schema in the page <head> or inline with the component. This enables Google's breadcrumb rich-result snippet.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://www.caatpension.ca/en.html"
},
{
"@type": "ListItem",
"position": 2,
"name": "Employers",
"item": "https://www.caatpension.ca/en/employers.html"
},
{
"@type": "ListItem",
"position": 3,
"name": "Pension Solutions",
"item": "https://www.caatpension.ca/en/employers/pension-solutions.html"
},
{
"@type": "ListItem",
"position": 4,
"name": "Contact"
}
]
}
</script>
| SEO Consideration | Details |
|---|---|
| Schema type | BreadcrumbList with ListItem entries |
| Last item | Omit the item URL for the current page (Google recommendation) |
| Canonical alignment | URLs in schema must match canonical URLs |
| Server-side rendering | Schema must be present in the initial HTML response (not injected via JS) |
10. Analytics
Analytics are captured through the shared data-analytics-component attribute on the component root (emitted automatically) and reported to the central data layer. Event names and payloads follow the organisation's standard analytics schema — defined centrally with the analytics team, not invented per component — so no bespoke tracking is specified here.
11. AEM Notes
| Item | Detail |
|---|---|
| Resource type | caat/components/breadcrumb |
| Sling model | Extend com.adobe.cq.wcm.core.components.models.Breadcrumb to add analytics attributes, full-label title values for visually truncated items, and JSON-LD schema output. |
| HTL template | breadcrumb.html — loops model.items, renders <nav> / <ol> structure. Last item emits aria-current="page". |
| Policy | Editable template policy: start level. (Separator is fixed — chevron; no truncation options.) |
| Client library | caat.breadcrumb — category caat.components. CSS only — no JS. |
| Migration | Replace legacy Breadcrumb (#1) instances. Run Groovy migration script to remap sling:resourceType. |
12. Dialog Model YAML
Simplified model — shows field intent and Granite UI resource types, not the literal cq:dialog node tree (e.g. select options are authored as child items nodes).
# _cq_dialog/.content.xml — represented as YAML
breadcrumb-dialog:
jcr:primaryType: nt:unstructured
sling:resourceType: cq/gui/components/authoring/dialog
extraClientlibs: "[caat.authoring]"
content:
jcr:primaryType: nt:unstructured
sling:resourceType: granite/ui/components/coral/foundation/container
items:
tabs:
jcr:primaryType: nt:unstructured
sling:resourceType: granite/ui/components/coral/foundation/tabs
items:
# ── Source tab ───────────────────────────────
source:
jcr:title: Source
items:
source:
sling:resourceType: granite/ui/components/coral/foundation/form/radiogroup
name: ./source
fieldLabel: Breadcrumb source
required: true
items:
- { text: Auto-generate from page hierarchy, value: auto, checked: true }
- { text: Manual override, value: manual }
startLevel:
sling:resourceType: granite/ui/components/coral/foundation/form/numberfield
name: ./startLevel
fieldLabel: Start level
value: 2
min: 1
max: 10
# ── Manual items tab ─────────────────────────
manualItems:
jcr:title: Manual Items
items:
items:
sling:resourceType: granite/ui/components/coral/foundation/form/multifield
name: ./items
fieldLabel: Breadcrumb items
composite: true
field:
sling:resourceType: granite/ui/components/coral/foundation/container
items:
label:
sling:resourceType: granite/ui/components/coral/foundation/form/textfield
name: ./label
fieldLabel: Label
required: true
url:
sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
name: ./url
fieldLabel: URL
required: true
13. QA Acceptance Checklist
- Breadcrumb renders with chevron separators by default — no modifier class or inline divider style present.
- Labels longer than 30 characters visually truncate with an ellipsis while the full label remains in the DOM and in
title. -
<nav aria-label="Breadcrumb">landmark is present. - Last item has
aria-current="page"and is not a link. - JSON-LD
BreadcrumbListschema is output in the page source and validates via Google Rich Results Test. -
data-analytics-*attributes are present on all ancestor links andbreadcrumb-clickevents fire to the data layer. - Auto-generated breadcrumb correctly reflects the AEM page tree from the configured start level.
- Manual override multifield produces the same HTML output with author-supplied labels and URLs.
- Focus ring is visible on all links and meets 3 : 1 contrast.
- Responsive: breadcrumb wraps gracefully on narrow viewports without horizontal overflow.
14. Definition of Done
| Area | Done means |
|---|---|
| Design | Figma component matches this chevron-only contract. Default and long-label truncation states are documented. Tokens are used — no hard-coded colour values. |
| Development | AEM component created extending Core Breadcrumb. HTL template emits semantic HTML per Section 6. CSS uses design tokens. Sling model outputs JSON-LD BreadcrumbList schema. Analytics data attributes wired. Legacy Breadcrumb (#1) replaced. Unit tests pass. |
| QA | All items in the QA Acceptance Checklist (Section 13) pass. Manual accessibility audit completed. Cross-browser tested (Chrome, Firefox, Safari, Edge). Screen reader tested with NVDA and VoiceOver. |
| Launch | Component deployed to AEM production. Legacy Breadcrumb component deprecated and migration script executed. Content authors trained on source selection and concise navigation titles. Analytics dashboards confirmed receiving breadcrumb-click events. |