Component Contract
Offcanvas
Slide-in side panel for supplementary content, filters, and contextual navigation across the CAAT Pension Plan member experience.
Demo
Rendered
Member Navigation
Rendered
Filter Member Resources
Resource Type
Rendered
Important Notices
Rendered
Cookie Preferences
CAAT Pension Plan uses cookies to enhance your experience. Manage your preferences below.
Panel Anatomy
The rendered panel appearance. The live panels above are slid in by Bootstrap (fixed-position) on trigger; this static instance shows the panel header, title, close button, and body for the Figma export.
Rendered
Member Navigation
1. Summary
The Offcanvas component provides a slide-in panel that appears from any edge of the viewport. It is designed for supplementary content that does not warrant a full page load — such as section navigation, resource filters, notification banners, and cookie consent panels within the CAAT Pension Plan member experience.
- Component name:
caat/components/offcanvas - Status: New
- Variants: Start (left), End (right), Top, Bottom
- Dependencies: Bootstrap 5.3.3 Offcanvas, CAAT Button component
- Usage context: Member portal navigation, resource filtering, system notifications, privacy consent
2. Design Tokens
| Token | Role | Example Value |
|---|---|---|
--caat-blue-900 | Panel title colour | #003750 |
--caat-blue-700 | Link/hover accent | #0b5a80 |
--caat-blue-100 | Active nav-link background highlight | #e7f4fb |
--caat-green | Success / confirmation states | #55a546 |
--caat-grey-200 | Header border, nav-link dividers | #dfe6ef |
--caat-focus | Focus ring on close button & interactive elements | #005FCC |
--caat-ink | Body text colour | #102637 |
--caat-radius | Border-radius for buttons & close button | .75rem |
--caat-font-primary | Font family for title and body | 'Libre Franklin' |
3. Authoring Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Title | Text | Yes | Rendered as the .caat-offcanvas__title. Max 60 characters. |
| Placement | Select | Yes | Options: Start, End, Top, Bottom. Defaults to Start. |
| Body Content | Rich Text | Yes | Supports links, lists, form elements. Injected into .caat-offcanvas__body. |
| Trigger Label | Text | Yes | Visible label for the trigger button. Must be descriptive. |
| Trigger Variant | Select | No | Button variant: primary, secondary, outline-primary. Defaults to primary. |
| Trigger Icon | Icon Picker | No | Bootstrap Icon class prepended to the trigger label. |
| Enable Backdrop | Toggle | No | Whether clicking outside closes the panel. Defaults to true. |
| Enable Scroll | Toggle | No | Allow body scroll while the offcanvas is open. Defaults to false. |
4. Validation Rules
| Rule | Constraint |
|---|---|
| Title required | Must not be blank. Used as aria-labelledby reference. |
| Title length | Maximum 60 characters to prevent header overflow. |
| Body content required | At least one block of content must be present. |
| Trigger label required | Empty trigger labels fail accessibility checks. |
| Unique ID | Each offcanvas instance on a page must have a unique ID attribute. |
| Placement value | Must be one of: start, end, top, bottom. |
5. Content Guidance
- Do use offcanvas for secondary content that supplements the main page — e.g., filters on a resource listing or contextual navigation in the member portal.
- Do keep the title concise and action-oriented (e.g., "Filter Resources", "Member Navigation").
- Do place the most important actions at the top of the body content so they are visible without scrolling.
- Don't use offcanvas for primary content that every member must see — use the main content area instead.
- Don't nest an offcanvas inside another offcanvas or inside a modal.
- Don't include complex multi-step forms; prefer linking to a dedicated form page.
- Tone: Friendly, clear, pension-literate. Align with the CAAT voice and tone guidelines.
6. Semantic HTML
<!-- Trigger -->
<button class="caat-button caat-button--primary"
type="button"
data-bs-toggle="offcanvas"
data-bs-target="#offcanvasExample"
aria-controls="offcanvasExample">
Open Panel
</button>
<!-- Offcanvas panel -->
<div class="offcanvas offcanvas-start caat-offcanvas"
tabindex="-1"
id="offcanvasExample"
aria-labelledby="offcanvasExampleLabel">
<div class="caat-offcanvas__header offcanvas-header">
<h5 class="caat-offcanvas__title" id="offcanvasExampleLabel">Panel Title</h5>
<button type="button"
class="caat-offcanvas__close"
data-bs-dismiss="offcanvas"
aria-label="Close">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="caat-offcanvas__body offcanvas-body">
<!-- Body content -->
</div>
</div>
7. CSS Contract
| Selector | Purpose |
|---|---|
.caat-offcanvas | Root panel — applies font, background, box-shadow. Extends Bootstrap .offcanvas. |
.caat-offcanvas__header | Panel header — white background, bottom border using --caat-grey-200. |
.caat-offcanvas__title | Title — font-weight: 800, color: var(--caat-blue-900). |
.caat-offcanvas__close | Close button — focus ring var(--caat-focus), hover accent --caat-blue-700. |
.caat-offcanvas__body | Body — font-family: var(--caat-font-primary), color: var(--caat-ink). |
Width: Side panels (start/end) render at 320px. Top/bottom panels cap at max-height: 50vh.
8. Accessibility
- The trigger button must include
aria-controlspointing to the offcanvas ID. - The panel must have
aria-labelledbyreferencing the title element'sid. tabindex="-1"is set on the panel root so focus is managed by Bootstrap.- When opened, focus moves into the panel. When closed, focus returns to the trigger button.
- The close button must have
aria-label="Close". - The Escape key must dismiss the panel (handled natively by Bootstrap).
- All interactive elements inside the body must be keyboard-accessible and have visible focus indicators using
--caat-focus. - Colour contrast for title text against white header exceeds WCAG 2.1 AA 4.5:1 ratio.
9. SEO
Transient / structural UI with no indexable content of its own — no SEO markup required. Ensure any content this component wraps or reveals stays server-rendered and crawlable.
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
- Resource type:
caat/components/offcanvas - Component group: CAAT — Overlays
- HTL template must emit the semantic HTML from Section 6. Placement class (
.offcanvas-start, etc.) is resolved via Sling model from the Placement dialog field. - The trigger button variant is driven by the Trigger Variant select field.
- A unique ID is auto-generated per component instance using
${component.id}. - Body content renders via an
Experience Fragmentor inline rich-text parsys, depending on author preference. - The offcanvas is compatible with AEM's responsive grid and should be placed outside the main content parsys to avoid stacking issues.
12. Dialog 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).
{
"title": { "type": "textfield", "required": true, "maxLength": 60 },
"placement": { "type": "select", "options": ["start","end","top","bottom"], "default": "start" },
"bodyContent": { "type": "richtext", "required": true },
"triggerLabel": { "type": "textfield", "required": true },
"triggerVariant": { "type": "select", "options": ["primary","secondary","outline-primary"], "default": "primary" },
"triggerIcon": { "type": "iconpicker", "required": false },
"enableBackdrop": { "type": "checkbox", "default": true },
"enableScroll": { "type": "checkbox", "default": false }
}
13. QA Checklist
| # | Check | Pass? |
|---|---|---|
| 1 | Panel opens from the correct edge matching the placement field. | |
| 2 | Close button, backdrop click, and Escape key all dismiss the panel. | |
| 3 | Focus moves into the panel on open and returns to the trigger on close. | |
| 4 | Title renders with font-weight: 800 and --caat-blue-900 colour. | |
| 5 | Side panels are 320 px wide; top/bottom panels cap at 50 vh. | |
| 6 | Body content scrolls internally when it overflows the panel height. | |
| 7 | All interactive elements show a visible focus ring using --caat-focus. | |
| 8 | Analytics events fire for open, close, link click, and filter apply. | |
| 9 | Component renders correctly on Chrome, Firefox, Safari, and Edge. | |
| 10 | No horizontal scroll or layout shift when the panel opens on mobile viewports. | |
| 11 | Screen reader announces panel title on open and "dismissed" on close. | |
| 12 | Multiple offcanvas instances on one page operate independently. |
14. Definition of Done
| Gate | Criteria |
|---|---|
| Design | Figma specs approved for all four placement variants. Token mapping reviewed. Responsive behaviour documented for mobile and tablet breakpoints. |
| Dev | AEM proxy component created. HTL template emits semantic HTML per Section 6. CSS uses design tokens exclusively. aria-labelledby and focus management wired. 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). |
| Launch | Component deployed to AEM production. Content authors trained on placement selection and body content authoring. Documentation published. Analytics dashboards confirmed receiving events. |