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.

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

ComponentBreadcrumb
ReplacesBreadcrumb (#1)
AEM TriageRebuild
PurposeShow 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 InteractionClick any ancestor link to navigate up the hierarchy. The current page is displayed as non-linked text at the end of the trail.
VariantsNone — 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 ruleRequired 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.

TokenRole
--caat-color-text-linkAncestor link colour
--caat-color-text-link-hoverLink hover colour
--caat-color-text-mutedCurrent-page text and separator colour
--caat-blue-700Eyebrow / accent (where used)
--caat-font-primaryTrail 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.

FieldTypeRequiredNotes
SourceRadio groupYesAuto-generate from page tree (default) or Manual override
Start LevelNumberYesDepth level at which the trail begins (default: 2, i.e. below the site root)
Manual Items (multifield)MultifieldNoOnly visible when Source = Manual override
 ↳ LabelTextYesDisplayed link text
 ↳ URLPathfieldYesInternal page path or external URL

4. Validation Rules

RuleSeverityDetails
At least one ancestor linkErrorBreadcrumb must contain at least a Home link before the current page.
Manual items: label requiredErrorEvery manual multifield entry must have a non-empty label.
Manual items: URL requiredErrorEvery manual item (except the last) must have a valid URL.
Start level ≥ 1ErrorStart level must be a positive integer.
Item length: 30-character visual capWarningLabels 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 IAErrorThe trail mirrors the content tree, which stops at L4 (max 5 items incl. Home) — no truncation pattern exists or is needed.
Present on L2+ pagesErrorTemplate policy: every Level 2, 3, and 4 page renders a breadcrumb; L1/home templates do not include the component.

5. Content Guidance

GuidelineDetails
LabelsUse concise page titles (2–4 words). Avoid repeating the site name. E.g. "Pension Solutions" not "CAAT Pension Solutions Page".
Home linkAlways start with "Home" as the first item linking to the site root.
Current pageDisplay as plain text (non-linked) and mark with aria-current="page".
Label lengthKeep navigation titles short; anything past 30 characters is cut with an ellipsis. Prefer a shorter navigation title over relying on truncation.
ConsistencyBreadcrumb 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

SelectorPurpose
.caat-breadcrumbWrapper <nav> — sets font-size, padding, and token-based colours.
.breadcrumbBootstrap's <ol> — inherits divider style and flex layout.
.breadcrumb-itemIndividual trail item. Applies link colour tokens and hover/focus states.
.breadcrumb-item.activeCurrent page item — non-linked, muted colour.
--bs-breadcrumb-dividerSet 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

RequirementImplementation
LandmarkWrap in <nav aria-label="Breadcrumb"> to expose a navigation landmark to assistive technologies.
Ordered listUse <ol> so screen readers announce the number of items and their position.
Current pageAdd aria-current="page" to the last <li> — the current page must not be a link.
Truncated labelsItems 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 contrastLink text must meet WCAG 2.1 AA — minimum 4.5 : 1 contrast against background.
Focus indicatorsAll links must show a visible focus ring meeting 3 : 1 contrast.
Structured dataInclude 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 ConsiderationDetails
Schema typeBreadcrumbList with ListItem entries
Last itemOmit the item URL for the current page (Google recommendation)
Canonical alignmentURLs in schema must match canonical URLs
Server-side renderingSchema 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

ItemDetail
Resource typecaat/components/breadcrumb
Sling modelExtend 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 templatebreadcrumb.html — loops model.items, renders <nav> / <ol> structure. Last item emits aria-current="page".
PolicyEditable template policy: start level. (Separator is fixed — chevron; no truncation options.)
Client librarycaat.breadcrumb — category caat.components. CSS only — no JS.
MigrationReplace 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 BreadcrumbList schema is output in the page source and validates via Google Rich Results Test.
  • data-analytics-* attributes are present on all ancestor links and breadcrumb-click events 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

AreaDone 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.