Component Contract

Navigation

Global navigation component covering the site header (navbar), footer, and mobile menu for the CAAT Pension Plan digital properties.

Live Demo

Desktop Mega Menu Navbar

Footer

The site footer is now its own component — see Footer. It composes Social/Share Links and is included by the page template, so Navigation no longer owns it.

Mobile Menu

Rendered

CAAT Pension Plan
Pension solutions
Why join
  • Flexibility
Members
Plan your retirement
Resources
Employers

Nav Link States

L1 navigation link interaction states. Hover and focus are shown statically via is-* classes mirroring the live :hover / :focus rules; the current-page state uses .active.

Code samples

Desktop Mega Menu Navbar HTML

<header class="caat-navbar" data-analytics-component="navigation">
  <div class="utility-bar">
    <div class="container d-flex justify-content-end gap-3">
      <a href="/contact">Contact us</a>
      <a href="#" class="lang-switch" aria-label="Switch language to French" lang="fr" hreflang="fr">Français</a>
    </div>
  </div>
  <nav class="navbar navbar-expand navbar-main" aria-label="Main navigation">
    <div class="container">
      <a class="navbar-brand" href="/">
        <img src="/assets/images/CAAT_RGB.png" alt="CAAT Pension Plan">
      </a>
      <div class="collapse navbar-collapse">
        <ul class="navbar-nav me-auto">
          <li class="nav-item dropdown">
            <div class="nav-link-group">
              <a class="nav-link" href="/pension-solutions">Pension solutions</a>
              <button class="nav-link nav-link-toggle dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Open Pension solutions menu"></button>
            </div>
            <div class="dropdown-menu mega-menu">
              <div class="container">
                <div class="mega-columns">
                  <div>
                    <!-- L2: clickable column header -->
                    <a class="mega-category-title" href="/pension-solutions/plans">
                      <i class="bi bi-shield-check"></i> Our Plans
                    </a>
                    <!-- L3: plain links — labels only, no descriptions, never L4 -->
                    <ul class="mega-links">
                      <li><a href="#">DBplus</a></li>
                      <li><a href="#">DBprime</a></li>
                    </ul>
                  </div>
                  <div class="mega-promo">
                    <p class="mega-promo-title">Ready to join?</p>
                    <p class="mega-promo-text">Learn more...</p>
                    <a href="#" class="btn btn-sm btn-primary">Get started</a>
                  </div>
                </div>
              </div>
            </div>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="/about">About us</a>
          </li>
        </ul>
        <div class="nav-actions">
          <div class="nav-search-wrap">
            <input type="search" class="nav-search-input"
                   placeholder="Search CAAT" aria-label="Search">
            <i class="bi bi-search"></i>
          </div>
          <div class="caat-dropdown dropdown">
            <button class="nav-login dropdown-toggle" type="button"
                    data-bs-toggle="dropdown" aria-expanded="false">
              <i class="bi bi-person-circle" aria-hidden="true"></i> Login
            </button>
            <ul class="dropdown-menu dropdown-menu-end caat-dropdown__menu">
              <li><a class="dropdown-item caat-dropdown__item" href="/member-portal">Member portal</a></li>
              <li><a class="dropdown-item caat-dropdown__item" href="/employer-portal">Employer Portal</a></li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </nav>
</header>

Footer markup

The footer is a separate component — see its full markup and contract on the Footer page.

Mobile drill-down — live demo

Scotiabank-style panel drill-down: tap a parent to slide into its child panel (down to Level 4), Back returns one level, each panel offers a section-overview link. Try it:

Menu
Pension solutions
Why join
  • Flexibility
Members
Plan your retirement
Resources
Employers

Mobile Menu HTML

<div class="caat-mobile-nav-demo">
  <div class="caat-mobile-topbar">
    <a href="/">
      <img src="/assets/images/caat-logo.jpg" alt="CAAT Pension Plan">
    </a>
    <button class="caat-menu-button" type="button"
            aria-expanded="false" aria-controls="mobileOffcanvas"
            aria-label="Open menu">
      <i class="bi bi-list" aria-hidden="true"></i> Menu
    </button>
  </div>
  <div class="offcanvas offcanvas-end" id="mobileOffcanvas"
       tabindex="-1" aria-labelledby="mobileOffcanvasLabel">
    <div class="offcanvas-header">
      <h5 id="mobileOffcanvasLabel">Menu</h5>
      <button type="button" class="btn-close"
              data-bs-dismiss="offcanvas" aria-label="Close"></button>
    </div>
    <div class="offcanvas-body caat-drillnav" data-caat-drillnav>
      <div class="caat-mobile-search">
        <input type="search" class="form-control"
               placeholder="Search CAAT" aria-label="Search CAAT">
        <i class="bi bi-search" aria-hidden="true"></i>
      </div>

      <!-- ROOT panel: L1 — items with children use a drill trigger -->
      <div class="caat-drillnav__panel">
        <ul class="caat-drillnav__list">
          <li>
            <button class="caat-drillnav__next" type="button"
                    data-target="dn-pension" aria-expanded="false">
              Pension solutions <i class="bi bi-chevron-right" aria-hidden="true"></i>
            </button>
          </li>
          <li><a class="caat-drillnav__link" href="/about">About CAAT</a></li>
        </ul>
      </div>

      <!-- L2 panel — Back + section overview link + children -->
      <div class="caat-drillnav__panel" id="dn-pension">
        <button class="caat-drillnav__back" type="button">
          <i class="bi bi-chevron-left" aria-hidden="true"></i> Back
        </button>
        <a class="caat-drillnav__overview" href="/pension-solutions">Pension solutions</a>
        <ul class="caat-drillnav__list">
          <li>
            <button class="caat-drillnav__next" type="button"
                    data-target="dn-dbplus" aria-expanded="false">
              DBplus <i class="bi bi-chevron-right" aria-hidden="true"></i>
            </button>
          </li>
          <li><a class="caat-drillnav__link" href="…">Why CAAT</a></li>
        </ul>
      </div>

      <!-- L3 panel — its links are L4 pages (deepest level) -->
      <div class="caat-drillnav__panel" id="dn-dbplus">
        <button class="caat-drillnav__back" type="button">
          <i class="bi bi-chevron-left" aria-hidden="true"></i> Back
        </button>
        <a class="caat-drillnav__overview" href="…">DBplus</a>
        <ul class="caat-drillnav__list">
          <li><a class="caat-drillnav__link" href="…">How DBplus works</a></li>
          <li><a class="caat-drillnav__link" href="…" aria-current="page">Contribution rates</a></li>
        </ul>
      </div>
    </div>
  </div>
</div>

1. Component Summary

Component nameNavigation
AEM component namecaat/components/navigation (covers header, footer, and mobile-nav as experience fragments)
Recommended implementationAEM Experience Fragments for Header and Footer, referenced globally via template policies
Component groupCAAT Design System
PurposeProvide consistent global navigation, wayfinding, and legal compliance across all pages
Existing AEM components replacedHeader (#39), Footer (#37)
AEM triage Rebuild Rebuild to new brand

Primary use cases

  1. Site header — desktop navbar with utility bar, 25% larger logo, mega-menu dropdowns (up to 4 columns, depth to L3), search, and a Login dropdown for the member and employer portals
  2. Mega menu panels — full-width dropdowns with categorised columns, nested links, optional promo cards, and L2-first keyboard tab order
  3. Site footer — link columns, legal links, social icons, and copyright
  4. Mobile navigation — offcanvas drill-down menu: one panel per level, forward to L4, Back returns a level (navigation.js)
  5. Utility navigation — secondary links (Contact, Support, Newsroom, Events, Careers)
  6. Language toggle — English / Français switcher with proper lang attribute

Non-goals

  1. Not for in-page section navigation (use Table of Contents component instead)
  2. Not for breadcrumbs (separate Breadcrumb component)
  3. Does not manage client-side routing or SPA behaviour

2. Design System Source / Token Dependencies

TokenValue (reference)Purpose
--caat-blue-900#003750Primary link hover, mobile menu button border, CTA background
--caat-blue-100#e7f4fbMobile panel gradient end, social icon hover background
--caat-blue-300#9dd2edMobile link hover border, search icon colour
--caat-grey-200#dfe6efBorders on navbar, footer, mobile links
--caat-lime#95e35cFooter heading indicator dot
--caat-green#55a546CTA alternate variant
--caat-radius-lg1.25remContainer border radius for nav sections
--caat-shadow-sm0 1px 3px rgba(0,0,0,.08)Subtle shadow on nav containers
--caat-focus0 0 0 .25rem rgba(47,149,210,.35)Focus ring on all interactive elements
--caat-muted#506273Search placeholder text
--caat-ink#102637Default text colour for mobile links
--caat-font-primary"Libre Franklin", Arial, sans-serifNavigation typeface

Visual variants

  • Desktop header — full-width navbar with dark utility bar, enlarged logo, mega-menu dropdown items (L1–L3), search pill, and a Login dropdown linking to both portals
  • Mega menu panel — full-width dropdown with up to 4 categorised columns containing L2 headings and L3 links, plus an optional promotional card
  • Mobile header — compact topbar with logo and hamburger toggle, offcanvas drill-down panels (to L4, with Back)
  • Full footer — 4-column link grid with legal row, social icons, copyright
  • Campaign footer — simplified single-row footer for landing pages (legal links + copyright only)

3. Authoring Fields

Header tab

FieldTypeRequiredDefaultNotes
Logo imageImage (DAM)YesCAAT logo. Rendered as <img> with alt text.
Primary nav linksMultifield (nested)YesEach L1 item: Label + URL + hasMegaMenu (toggle). If mega menu enabled, add L2 Categories multifield (title + URL + icon — the column header is a link) with an L3 Links multifield [label + URL only — no descriptions, no L4 sub-links]. Min 3, max 7 L1 items.
Mega menu promo cardCompositeNoPer L1 mega item: Title (text) + Description (textarea) + CTA label + CTA URL. Renders as a featured card in the last column of the mega panel.
Utility nav linksMultifieldNoEach item: Label (text) + URL (pathfield). Rendered above main row.
Search enabledToggleNoOnShow/hide the search field in the navbar.
Member portal URLPath browserYesDestination for the “Member portal” item in the Login dropdown.
Employer Portal URLPath browserYesDestination for the “Employer Portal” item in the Login dropdown.
Language toggle URLsMultifieldNoEach item: Language code + URL. Uses lang attribute.

Footer tab

FieldTypeRequiredDefaultNotes
Link columnsMultifieldYesEach column: Heading (text) + Links multifield (label + URL). Max 4 columns.
Legal linksMultifieldYesEach item: Label + URL. Must include Privacy, Terms of use, Accessibility.
Social linksMultifieldNoEach item: Platform (dropdown) + URL. Provides icon and aria-label automatically.
Logo imageImage (DAM)YesFooter logo. Typically same as header.
Copyright textText fieldYese.g. "© 2026 CAAT Pension Plan. All rights reserved."

Mobile tab

FieldTypeRequiredDefaultNotes
Inherits from headerPrimary links, utility links, search, portal Login dropdown, and language toggle are inherited from the Header tab.
Offcanvas positionSelectNoEnd (right)start | end. Controls which side the offcanvas panel slides in from.

4. Authoring Validation Rules

  1. Logo image is required for both header and footer. The dialog must not allow saving without it.
  2. Primary nav links must contain at least 3 items. Display a validation error if fewer are provided.
  3. Footer legal links must include entries for Privacy, Terms of use, and Accessibility. Warn if any are missing.
  4. Copyright text is required. The dialog must not allow saving without it.
  5. Social links must each have a valid URL and an aria-label generated from the selected platform name.
  6. Both portal URLs are required so the Login dropdown always contains “Member portal” and “Employer Portal”.
  7. Primary nav link labels should not exceed 25 characters each. Display a warning above 20 characters.
  8. Mega menu columns: a menu may contain at most 4 link groups (columns). The dialog rejects a 5th group.
  9. Mega menu depth: entries go no deeper than Level 3 (column header = clickable L2 link, list links = L3 labels only — no descriptions). L4 pages never appear in the mega menu — they are reached via the Side Navigation, breadcrumb, and the mobile drill-down.
  10. Mega menu keyboard order: inside each open desktop panel, Tab reaches every clickable L2 column header first, then continues through L3 links and promo links.
  11. Mobile drill-down depth: panels mirror the full tree to Level 4; every drilled panel must include the Back control and a section-overview link.

5. Content Guidance

Good examples

  • Navigation labels consistent with site map
  • Short, scannable utility link labels
  • Visible "Menu" text label on mobile hamburger button
  • Footer columns match primary site sections
  • Language toggle clearly identifies target language
  • Split L1 items keep the text link navigable while the adjacent caret controls the mega panel

Avoid

  • Hamburger icon without visible text label
  • Removing legal links from campaign pages without approval
  • Inconsistent nav labels between header and footer
  • More than 7 primary navigation items
  • Using abbreviations in navigation labels
  • Making the L1 text link a dropdown-only trigger; it must remain a real landing-page link

Interaction expectations

  • On desktop, hovering a mega-menu L1 item opens its panel after a short intent delay.
  • The L1 text remains a normal link to the section landing page. Hover must not prevent click navigation.
  • The adjacent caret button toggles the same panel for pointer and keyboard users and mirrors state with aria-expanded.
  • Only one mega panel may be open at a time. Moving to another L1 opens that panel and closes the previous panel.
  • Hover-open is desktop-only. Tablet and mobile use the offcanvas drill-down menu.

6. Expected Semantic HTML Output

Header — Bootstrap navbar with mega menu

<header class="caat-navbar">
  <!-- Utility bar -->
  <div class="utility-bar">
    <div class="container d-flex justify-content-end gap-3">
      <a href="#">Contact us</a>
      <a href="#" class="lang-switch" aria-label="Switch language to French" lang="fr" hreflang="fr">Français</a>
    </div>
  </div>
  <!-- Main navbar -->
  <nav class="navbar navbar-expand navbar-main" aria-label="Main navigation">
    <div class="container">
      <a class="navbar-brand" href="/">
        <img src="/logo.png" alt="CAAT Pension Plan">
      </a>
      <div class="collapse navbar-collapse">
        <ul class="navbar-nav me-auto">
          <li class="nav-item dropdown">
            <div class="nav-link-group">
              <a class="nav-link" href="/pension-solutions">Pension solutions</a>
              <button class="nav-link nav-link-toggle dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Open Pension solutions menu"></button>
            </div>
            <div class="dropdown-menu mega-menu">
              <div class="container">
                <div class="mega-columns">
                  <div>
                    <a class="mega-category-title" href="…">Our Plans</a>  <!-- L2, clickable -->
                    <ul class="mega-links">                                 <!-- L3, labels only -->
                      <li><a href="#">DBplus</a></li>
                    </ul>
                  </div>
                  <div class="mega-promo">…</div>
                </div>
              </div>
            </div>
          </li>
          <li class="nav-item"><a class="nav-link" href="#">About</a></li>
        </ul>
        <div class="nav-actions">
          <div class="nav-search-wrap">
            <input type="search" class="nav-search-input">
            <i class="bi bi-search"></i>
          </div>
          <div class="caat-dropdown dropdown">
            <button class="nav-login dropdown-toggle" type="button"
                    data-bs-toggle="dropdown" aria-expanded="false">Login</button>
            <ul class="dropdown-menu dropdown-menu-end caat-dropdown__menu">
              <li><a class="dropdown-item caat-dropdown__item" href="/member-portal">Member portal</a></li>
              <li><a class="dropdown-item caat-dropdown__item" href="/employer-portal">Employer Portal</a></li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </nav>
</header>

Navigation hierarchy (IA is 4 levels; the mega menu shows L1–L3)

LevelElementCSS classExample
L1<li class="nav-item dropdown">.nav-itemPension solutions, Members
L2<a class="mega-category-title" href>clickable column header linking to the L2 landing page.mega-category-titleWhy join, Life events
L3<ul class="mega-links"> <li><a>.mega-links aSuccess stories, Estimate your pension
L4Never rendered in the mega menu. L4 pages are reached via the Side Navigation, breadcrumb, and the mobile drill-down.

Footer — semantic <footer> with <nav>

<footer class="caat-footer" role="contentinfo">
  <div class="container">
    <div class="caat-footer__grid">
      <nav class="caat-footer__col" aria-labelledby="ft-quick">
        <h2 class="caat-footer__heading" id="ft-quick">Quick links</h2>
        <ul class="caat-footer__list">…</ul>
      </nav>
    </div>
    <div class="caat-footer__bottom">…</div>
  </div>
</footer>

Full contract on the Footer page.

Mobile menu — offcanvas with ARIA

<button class="caat-menu-button" type="button"
        data-bs-toggle="offcanvas" data-bs-target="#mobileOffcanvas"
        aria-expanded="false" aria-controls="mobileOffcanvas"
        aria-label="Open menu">
  <i class="bi bi-list" aria-hidden="true"></i> Menu
</button>

<div class="offcanvas offcanvas-end" id="mobileOffcanvas"
     tabindex="-1" aria-labelledby="mobileOffcanvasLabel">
  <div class="offcanvas-header">
    <h5 id="mobileOffcanvasLabel">Menu</h5>
    <button type="button" class="btn-close"
            data-bs-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body caat-drillnav" data-caat-drillnav>
    <div class="caat-drillnav__panel">…</div>   <!-- root + one panel per node, see §6 -->
  </div>
</div>

7. CSS Contract

The navigation component relies on the global token layer defined in /assets/css/tokens.css. All component-specific styles live in /assets/css/components/navigation.css.

Primary selectors

SelectorPurpose
.caat-navbarTop-level navbar wrapper (<header>)
.caat-navbar .utility-barDark, right-aligned utility links bar (top row)
.caat-navbar .navbar-mainMain nav row (Bootstrap .navbar)
.caat-navbar .mega-menuFull-width mega dropdown panel (extends .dropdown-menu)
.mega-columnsCSS Grid container for mega menu columns
.mega-category-titleClickable L2 column header (<a> to the L2 landing page) — icon + lime underline
.mega-linksL3 link list within a mega column
.mega-promoOptional promotional card inside mega panel
.nav-actionsRight-side actions: search and the composed Dropdown component for portal login
.nav-search-inputPill-shaped search field (expands on focus)
(footer)Moved to the standalone .caat-footer component
.caat-mobile-nav-demoMobile navigation demo container
.caat-drillnav [data-caat-drillnav]Mobile drill-down container (offcanvas body)
.caat-drillnav__panelOne panel per node with children; first = root (L1)
.caat-drillnav__next / __backDrill trigger (data-target, aria-expanded) / back control
.caat-drillnav__overview / __linkSection landing link at panel top / leaf link
Note: Do not duplicate token values inside the component CSS. Always reference the custom property (e.g. var(--caat-blue-900)) so that theme changes propagate automatically.

8. Accessibility Requirements

RequirementAcceptance criteria
Skip link A "Skip to main content" link must be the first focusable element on the page, targeting the #main landmark.
Keyboard navigation All interactive elements (links, buttons, search input) must be reachable and operable via Tab, Enter, Space, and Escape (to close offcanvas). Inside desktop mega menus, Tab moves across all L2 category links first, then through the L3 links and promo links.
Visible focus states A visible focus ring (var(--caat-focus)) must appear on :focus-visible for all interactive elements. The ring must meet a 3 : 1 contrast ratio.
Mobile toggle — aria-expanded The mobile Menu button must toggle aria-expanded between true and false. It must reference the offcanvas panel via aria-controls.
Social link labels Every social icon link must have an aria-label (e.g. "CAAT on LinkedIn"). The icon must have aria-hidden="true".
Language toggle The language toggle link must spell out the language names and use the lang attribute matching the target language (e.g. lang="fr").
Nav landmarks Each <nav> must have a unique aria-label (e.g. "Main navigation", "Footer navigation", "Legal links").
Colour contrast All text and interactive elements must meet WCAG 2.1 AA (4.5 : 1 normal text, 3 : 1 large text) in all states.

Behaviour contract

Bootstrap 5 handles offcanvas lifecycle and the Login dropdown. navigation.js handles the split-link desktop mega menus, mobile drill-down panels, and desktop mega-menu tab order. Verify the behaviours below survive any AEM integration.

BehaviourMechanism & acceptance criteria
Mobile menuBelow lg (992 px) the bar collapses behind a Menu button that opens the offcanvas (aria-expanded + aria-controls). Above it, the full bar renders and the toggler is hidden.
Mobile drill-down (navigation.js)Inside the offcanvas: .caat-drillnav__next reveals the child panel (to L4) and focuses its Back control; .caat-drillnav__back returns one level and restores focus to the trigger; Escape in a sub-panel goes back one level (closes the offcanvas only from the root); closing the offcanvas resets to the root panel. Hidden panels use the hidden attribute; triggers mirror state via aria-expanded.
Desktop hover-openOn viewports at or above lg (992 px), pointer hover on a mega-menu L1 item opens its panel after a short intent delay. The panel remains open while the pointer is over the L1 item or its mega panel, then closes after a short delay when the pointer leaves both. Hover must not apply below lg.
Mega menu caret toggleL1 text links navigate to the landing page. The adjacent caret button toggles the same mega panel on click/Enter/Space and mirrors state with aria-expanded. navigation.js closes the panel on Escape with focus returned to the caret, closes on outside click, and keeps only one panel open at a time.
Keyboard inside menusInside open desktop mega menus, navigation.js intercepts Tab so focus traverses all .mega-category-title L2 links across the panel first, then continues through L3 links and promo links. Shift+Tab reverses that order.
Sticky headersticky-top (z-index 1020 = --caat-z-sticky). Anchor targets stay visible beneath it via the global scroll-padding-top: 5rem (caat-base.css).
Current pageSet aria-current="page" + the .active class on the current L1 link (server-rendered, not JS-derived).

9. SEO Requirements

  1. All navigation links must be rendered as crawlable <a> elements with valid href attributes. No JavaScript-only navigation.
  2. Link text must be descriptive and unique within the page. Avoid generic phrases like "Click here".
  3. Maintain a canonical navigation structure — the same primary links should appear on all pages for consistent internal linking.
  4. Footer links contribute to the site's internal link graph. Ensure all footer URLs resolve correctly (no broken links).
  5. The logo link should point to the site root (/) to reinforce the homepage's authority.

10. Analytics Requirements

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 Implementation Notes

Existing component mapping

This component replaces Header (#39) and Footer (#37) in the existing AEM component library.

AEM triage

Rebuild Rebuild to new brand standards. The existing header and footer components do not meet current accessibility, design-token, or responsive requirements.

Experience Fragment approach

Implement the header and footer as AEM Experience Fragments. Each fragment is authored once and referenced globally via template policies, ensuring consistent navigation across all pages without per-page authoring.

  • Header XF: contains the desktop mega-menu navbar (Bootstrap 5.3 navbar-expand with .dropdown-menu.mega-menu panels). Mobile nav uses Bootstrap offcanvas + the drill-down panels; navigation.js also normalizes desktop mega-menu tab order.
  • Footer XF: contains the full footer; campaign pages may reference a simplified campaign-footer XF variant.

Client library structure

  • Category: caat.components.navigation
  • Dependencies: caat.base (tokens + base styles), caat.components.button, and caat.components.dropdown for the portal Login control
  • CSS: navigation.css
  • JS: navigation.js (Bootstrap 5.3 bundle handles dropdown/offcanvas show-hide natively; navigation.js normalizes desktop mega-menu tab order and implements the mobile drill-down — panel stack, Back, focus management, reset on close)

Suggested file structure

experience-fragments/
├── header/
│   ├── master/
│   │   ├── _cq_dialog/
│   │   │   └── .content.xml        # Header XF dialog
│   │   ├── .content.xml             # XF node definition
│   │   └── header.html              # HTL template
│   └── variations/
│       └── campaign-header/
│           └── .content.xml
├── footer/
│   ├── master/
│   │   ├── _cq_dialog/
│   │   │   └── .content.xml        # Footer XF dialog
│   │   ├── .content.xml
│   │   └── footer.html
│   └── variations/
│       └── campaign-footer/
│           └── .content.xml
└── clientlibs/
    ├── .content.xml
    ├── css/
    │   └── navigation.css
    └── js/
        └── navigation.js

12. Dialog Field Model

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

# caat/experience-fragments/header — Touch UI Dialog
# _cq_dialog/.content.xml (YAML representation)

dialog:
  jcr:primaryType: nt:unstructured
  sling:resourceType: cq/gui/components/authoring/dialog
  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:

          # ── Header tab ───────────────────────────────
          header:
            jcr:title: Header
            items:
              logoImage:
                sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                name: ./logoImage
                fieldLabel: Logo image
                required: true
                rootPath: /content/dam
              primaryNavLinks:
                sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                name: ./primaryNavLinks
                fieldLabel: Primary nav links
                required: true
                composite: true
                items:
                  label:
                    sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                    name: ./label
                    fieldLabel: Label
                    required: true
                    maxlength: 25
                  url:
                    sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                    name: ./url
                    fieldLabel: URL
                    required: true
              utilityNavLinks:
                sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                name: ./utilityNavLinks
                fieldLabel: Utility nav links
                composite: true
                items:
                  label:
                    sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                    name: ./label
                    fieldLabel: Label
                  url:
                    sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                    name: ./url
                    fieldLabel: URL
              searchEnabled:
                sling:resourceType: granite/ui/components/coral/foundation/form/switch
                name: ./searchEnabled
                fieldLabel: Search enabled
                checked: true
              memberPortalURL:
                sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                name: ./memberPortalURL
                fieldLabel: Member portal URL
                required: true
              employerPortalURL:
                sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                name: ./employerPortalURL
                fieldLabel: Employer Portal URL
                required: true
              languageToggleURLs:
                sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                name: ./languageToggleURLs
                fieldLabel: Language toggle URLs
                composite: true
                items:
                  langCode:
                    sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                    name: ./langCode
                    fieldLabel: Language code
                  url:
                    sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                    name: ./url
                    fieldLabel: URL

          # ── Mobile tab ───────────────────────────────
          mobile:
            jcr:title: Mobile
            items:
              offcanvasPosition:
                sling:resourceType: granite/ui/components/coral/foundation/form/select
                name: ./offcanvasPosition
                fieldLabel: Offcanvas position
                items:
                  - { text: End (right), value: end }
                  - { text: Start (left), value: start }

---

# caat/experience-fragments/footer — Touch UI Dialog
# _cq_dialog/.content.xml (YAML representation)

dialog:
  jcr:primaryType: nt:unstructured
  sling:resourceType: cq/gui/components/authoring/dialog
  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:

          # ── Footer tab ──────────────────────────────
          footer:
            jcr:title: Footer
            items:
              linkColumns:
                sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                name: ./linkColumns
                fieldLabel: Link columns
                required: true
                composite: true
                items:
                  heading:
                    sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                    name: ./heading
                    fieldLabel: Column heading
                    required: true
                  links:
                    sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                    name: ./links
                    fieldLabel: Links
                    composite: true
                    items:
                      label:
                        sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                        name: ./label
                        fieldLabel: Label
                      url:
                        sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                        name: ./url
                        fieldLabel: URL
              legalLinks:
                sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                name: ./legalLinks
                fieldLabel: Legal links
                required: true
                composite: true
                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
              socialLinks:
                sling:resourceType: granite/ui/components/coral/foundation/form/multifield
                name: ./socialLinks
                fieldLabel: Social links
                composite: true
                items:
                  platform:
                    sling:resourceType: granite/ui/components/coral/foundation/form/select
                    name: ./platform
                    fieldLabel: Platform
                    items:
                      - { text: LinkedIn, value: linkedin }
                      - { text: YouTube, value: youtube }
                      - { text: Twitter / X, value: twitter }
                      - { text: Facebook, value: facebook }
                      - { text: Instagram, value: instagram }
                  url:
                    sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                    name: ./url
                    fieldLabel: URL
              footerLogo:
                sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                name: ./footerLogo
                fieldLabel: Logo image
                required: true
                rootPath: /content/dam
              copyrightText:
                sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                name: ./copyrightText
                fieldLabel: Copyright text
                required: true

13. QA Acceptance Checklist

  • Desktop navbar renders correctly: dark right-aligned utility bar, enlarged logo, split L1 navigation links, search pill, Login dropdown, and language toggle are visible and properly aligned; no Join DBplus button renders.
  • Login uses the Dropdown component and contains exactly two links: “Member portal” and “Employer Portal”.
  • Desktop mega menu panels open on L1 hover and on caret click/keyboard activation. The L1 text link remains clickable and navigates to its landing page.
  • Mega menu panels display categorised columns (L2 headings and L3 links only) and an optional promo card.
  • Mega menu closes on pointer leave, outside click, Escape key, or opening another L1 item. Only one panel is open at a time.
  • Mobile menu opens via hamburger toggle; the search field appears at the top of the drawer; drill-down panels reach L4 with a working Back control, focus moves into each revealed panel, and the menu resets to root on close.
  • Full footer renders all 4 link columns, legal links (including Privacy, Terms of use, Accessibility), social icons, logo, and copyright.
  • Responsive behaviour: navbar wraps gracefully at tablet and mobile breakpoints; footer collapses to 2-column and then 1-column; mobile nav is hidden on desktop.
  • Keyboard navigation works: all links and buttons reachable via Tab; desktop mega menu focus moves across L2 category links before L3 links; offcanvas closes with Escape; focus is trapped inside offcanvas when open.
  • All links resolve correctly — no broken links in header, footer, or mobile menu. External links open in new tab with rel="noopener".
  • Legal compliance: Privacy, Terms of use, and Accessibility links are present in the footer on all page templates including campaign pages.
  • Language toggle switches to the correct locale URL and uses the lang attribute on the toggle element.

14. Definition of Done

AreaDone means
Design Figma component matches this contract. Desktop navbar, mobile menu, full footer, and campaign footer variants are documented. All tokens are used — no hard-coded colour values.
Development AEM Experience Fragments created for header and footer. HTL templates emit semantic HTML per Section 6. CSS uses design tokens. JS wires analytics events and mobile offcanvas. Unit tests pass.
QA All items in the QA Acceptance Checklist (Section 13) pass, including desktop hover-open, caret toggle, L1 link navigation, L2-first mega-menu keyboard order, mobile drill-down focus restoration, and breadcrumb/side-nav handoff checks. Manual accessibility audit completed. Cross-browser tested (Chrome, Firefox, Safari, Edge). Responsive tested at 320px, 768px, 1024px, 1440px.
Launch Experience Fragments deployed to AEM production. Template policies configured to reference header/footer globally. Content authors trained. Analytics dashboards confirmed receiving nav-click, footer-click, and mobile-menu-open events.