Component Contract

Card

A flexible content-grouping component for displaying headings, summaries, images, icons, and links across CAAT digital properties.

Live Demo

Icon cards

Rendered

For employers

Discover how CAAT helps you offer a secure, sustainable pension plan to your employees.

Explore employer solutions

Plan performance

Review our investment strategy, funding status, and annual performance reports.

View plan performance

Image cards

Rendered

Couple reviewing financial documents at a kitchen table
Resources

Retirement planning guide

Everything you need to know about planning for a secure retirement with CAAT.

Read the guide
Data charts displayed on a laptop screen
Reports

2025 Annual report

Review CAAT's investment performance, membership growth, and financial highlights.

Download the report

Media overlay card

Rendered

Presenter speaking at a corporate webinar event
Upcoming event

Pension planning webinar — June 2026

Join our experts for a live session on maximising your CAAT pension benefits.

Register for the event

Use-case patterns — image aspect ratios

Each card type uses one standard ratio from the Card Image Ratios foundation. One ratio per grid.

Blog listing — 16:9

Rendered

Team reviewing charts in a meeting
Insights

Why DB plans win talent

How a modern pension shifts the recruiting equation.

Two colleagues talking at a desk
Research

The retirement gap in 2026

New data on Canadians' retirement readiness.

People collaborating in an office
News

DBplus reaches 100k members

A milestone for Canada's modern pension.

Leadership bios — 1:1, face-centred

Rendered

Margaret Chen

Margaret Chen

Chief Investment Officer

David Okafor

David Okafor

VP, Member Services

Priya Sharma

Priya Sharma

Head of Plan Design

James Wright

James Wright

General Counsel

Resource call-outs — 4:3

States

Rendered

Secure pension

Your pension is backed by a robust funding framework.

Secure pension

Your pension is backed by a robust funding framework.

Code sample

HTML

<!-- Icon card -->
<article class="card caat-card"
         data-analytics-component="card"
         data-analytics-category="icon-card"
         data-analytics-label="for-members">
  <div class="card-body text-center">
    <span class="icon-token mb-3" aria-hidden="true">
      <i class="bi bi-people-fill"></i>
    </span>
    <h3 class="card-title">For members</h3>
    <p class="card-text">Access your pension information…</p>
    <a href="/en/members" class="stretched-link">Learn more</a>
  </div>
</article>

<!-- Image card with kicker -->
<article class="card caat-card">
  <img src="/content/dam/caat/images/hero.jpg"
       class="card-img-top"
       alt="Descriptive alt text">
  <div class="card-body">
    <span class="caat-card-kicker">Resources</span>
    <h3 class="card-title">Retirement planning guide</h3>
    <p class="card-text">Everything you need to know…</p>
    <a href="/en/resources/guide" class="stretched-link">Read the guide</a>
  </div>
</article>

<!-- Media overlay card -->
<article class="card caat-card caat-card--overlay">
  <img src="/content/dam/caat/images/event.jpg"
       class="card-img"
       alt="Presenter at corporate event">
  <div class="card-img-overlay overlay-panel d-flex flex-column justify-content-end">
    <span class="caat-card-kicker text-white">Event</span>
    <h3 class="card-title text-white">Pension webinar</h3>
    <p class="card-text text-white">Join our experts…</p>
    <a href="/en/events/webinar" class="stretched-link text-white">Register</a>
  </div>
</article>

1. Component Summary

Component nameCard
AEM component namecaat/components/card
Recommended implementationExtend the AEM Core Teaser component (core/wcm/components/teaser/v2/teaser)
Component groupCAAT Design System
PurposeDisplay grouped content with a heading, summary, image or icon, and link — suitable for value propositions, resource listings, event promotions, and audience pathway navigation
Existing AEM components replacedCard Grid Component (#25), Container with Card Style (#28), Multi Tile Listing (#43)

Primary use cases

  1. Value proposition cards (icon-based, 3-up or 4-up grid)
  2. Resource cards with images (guides, reports, articles)
  3. Event cards with date and registration link
  4. Audience pathway cards (For members, For employers)
  5. Content listing cards (blog, news)
  6. Media overlay cards (featured content with background image)

Non-goals

  1. This component is not for navigation menus — use the Navigation component
  2. It is not a form container — use the Form component for data collection
  3. It is not for hero-level messaging — use the Hero component for full-width feature areas
  4. It does not manage interactive carousels or sliders
  5. It does not replace inline content blocks or rich-text sections

2. Design System Source / Token Dependencies

TokenValue (reference)Purpose
--caat-grey-200#dfe6efCard border colour
--caat-blue-100#e7f4fbIcon-token background tint
--caat-blue-300#9dd2edIcon-token icon colour
--caat-blue-900#003750Card heading colour, link colour
--caat-green-100#e8f5e6Kicker background tint
--caat-green-700#367f32Kicker text colour
--caat-blue-700#0b5a80Link hover colour
--caat-radius.75remCard border radius (standard)
--caat-radius-lg1.25remCard border radius (large / overlay variant)
--caat-shadow0 .5rem 1rem rgba(0,0,0,.08)Card hover elevation shadow
--caat-shadow-sm0 .125rem .25rem rgba(0,0,0,.05)Card resting shadow

Visual variants

  • Icon card — centred layout with icon-token, heading, summary, and stretched link
  • Image card — top image with card-body containing optional kicker, heading, summary, and link
  • Media overlay — full-bleed background image with overlay-panel containing heading and link
  • Content card — text-only card without image or icon

Sizes

  • Standard — default card height, auto-sized to content
  • Compact (.caat-card--compact) — reduced padding and smaller typography for dense layouts

3. Authoring Fields

Content tab

FieldTypeRequiredDefaultNotes
HeadingText fieldYesCard title. Max 80 characters recommended.
Heading levelDropdownNoh3h2 | h3 | h4. Allows authors to maintain heading hierarchy.
SummaryText areaNoShort description. Max 160 characters recommended.
Link URLPath browserYes*Required for clickable cards. Internal or external URL.
Link labelText fieldNoVisible link text. If empty, the stretched-link is visually hidden but accessible.
ImageImage pickerNoDAM image reference. Used for Image and Overlay variants.
Image alt textText fieldConditionalRequired when an image is provided. Decorative images should use empty alt.
KickerText fieldNoSmall label above heading (e.g. "Resources", "Event"). Max 3 words.
IconDropdownNoNoneIcon for the Icon card variant. Options: none, people, building, graph, shield, calendar, document.

Style tab

FieldTypeRequiredDefaultNotes
VariantDropdownYesImage cardicon | image | overlay | content
Card heightDropdownNoAutoauto | fixed (equal-height cards in a row)
Image aspect ratioDropdownNo16:916:9 | 4:3 | 1:1. Only shown for Image and Overlay variants.

Behaviour tab

FieldTypeRequiredDefaultNotes
Link targetCheckboxNoSame tabIf checked, opens in new tab and adds rel="noopener".
Analytics labelText fieldNoCustom label for analytics reporting. Auto-generated from heading if empty.

4. Authoring Validation Rules

  1. Heading is required. The dialog must not allow saving without it.
  2. Link URL is required for clickable cards. If no URL is provided, the card renders as a static (non-linked) block.
  3. Image alt text is required when an image is present. The dialog must display a warning if the image field is populated but alt text is empty.
  4. Kicker must not exceed 3 words. Display a validation warning if exceeded.
  5. Overlay cards must have sufficient text-to-background contrast. The overlay-panel gradient must ensure a minimum 4.5 : 1 contrast ratio for body text.
  6. If Link target is set to "New tab", the system must automatically append rel="noopener" to the rendered anchor.

5. Content Guidance

Good examples

  • "Explore pension solutions"
  • "Register for the event"
  • "Download the guide"
  • "View 2025 annual report"
  • "Learn about employer benefits"

Avoid

  • "Click here"
  • "Read more" (without context)
  • Mixing unrelated content types in the same card row
  • Using overlay cards without high-contrast gradient
  • Kickers longer than 3 words

6. Expected Semantic HTML Output

Icon card

<article class="card caat-card">
  <div class="card-body text-center">
    <span class="icon-token" aria-hidden="true">
      <i class="bi bi-people-fill"></i>
    </span>
    <h3 class="card-title">For members</h3>
    <p class="card-text">Access your pension information and tools.</p>
    <a href="/en/members" class="stretched-link">Learn more about member benefits</a>
  </div>
</article>

Image card with kicker

<article class="card caat-card">
  <img src="/content/dam/caat/images/guide.jpg"
       class="card-img-top"
       alt="Couple reviewing financial documents">
  <div class="card-body">
    <span class="caat-card-kicker">Resources</span>
    <h3 class="card-title">Retirement planning guide</h3>
    <p class="card-text">Everything you need to plan your retirement.</p>
    <a href="/en/resources/guide" class="stretched-link">Read the guide</a>
  </div>
</article>

Media overlay card

<article class="card caat-card caat-card--overlay">
  <img src="/content/dam/caat/images/event.jpg"
       class="card-img"
       alt="Presenter at corporate webinar">
  <div class="card-img-overlay overlay-panel d-flex flex-column justify-content-end">
    <span class="caat-card-kicker text-white">Upcoming event</span>
    <h3 class="card-title text-white">Pension planning webinar</h3>
    <p class="card-text text-white">Join our experts for a live session.</p>
    <a href="/en/events/webinar" class="stretched-link text-white">Register</a>
  </div>
</article>

7. CSS Contract

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

Base styles

.caat-card {
  border: 1px solid var(--caat-grey-200, #e9ecef);
  border-radius: var(--caat-radius, .75rem);
  box-shadow: var(--caat-shadow-sm);
  transition: box-shadow .18s ease, transform .18s ease;
  overflow: hidden;
}

.caat-card:hover {
  box-shadow: var(--caat-shadow);
  transform: translateY(-2px);
}

/* Icon token */
.caat-card .icon-token {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background: var(--caat-blue-100);
  color: var(--caat-blue-300);
  font-size: 1.5rem;
}

/* Kicker */
.caat-card-kicker {
  display: inline-block;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--caat-green-700);
  margin-bottom: .5rem;
}

/* Overlay variant */
.caat-card--overlay {
  border-radius: var(--caat-radius-lg, 1rem);
}

.caat-card--overlay .overlay-panel {
  background: linear-gradient(to top, rgba(0,55,80,.85) 0%, transparent 100%);
  padding: 1.5rem;
}

/* Focus ring on stretched-link */
.caat-card .stretched-link:focus-visible {
  box-shadow: var(--caat-focus);
  outline: 0;
}

/* Image — pick ONE ratio per grid (see Card Image Ratios foundation).
   A ratio modifier is required (legacy fixed heights have been removed). */
.caat-card-image          { width: 100%; object-fit: cover; }
.caat-card-image--16-9    { aspect-ratio: 16 / 9; }   /* blog / article cards */
.caat-card-image--4-3     { aspect-ratio: 4 / 3;  }   /* resource call-outs   */
.caat-card-image--1-1     { aspect-ratio: 1 / 1;  }   /* bios / thumbnails    */
.caat-card-image--4-5     { aspect-ratio: 4 / 5;  }   /* editorial portrait   */
.caat-card-image--3-2     { aspect-ratio: 3 / 2;  }   /* editorial photography*/
.caat-card-image--face    { object-position: 50% 22%; } /* keep faces in frame */
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
Keyboard access Cards using .stretched-link must be focusable and activatable via Tab and Enter. The entire card surface acts as the hit area.
Focus state A visible focus ring (var(--caat-focus)) must appear on the stretched-link on :focus-visible. The ring must meet a 3 : 1 contrast ratio.
Image alt text All card images must have descriptive alt text. Purely decorative images may use alt="" but must not omit the attribute.
Heading hierarchy Card headings must fit within the page's heading hierarchy. Authors can choose h2, h3, or h4 via the authoring dialog.
Article landmark Each card is rendered as an <article> element, providing a meaningful landmark for assistive technologies.
Colour contrast Text-to-background contrast must meet WCAG 2.1 AA in all variants, including overlay cards with gradient backgrounds.

9. SEO Requirements

  1. Use descriptive, keyword-rich headings in card titles. Avoid generic text.
  2. All card links must use real href attributes that resolve to valid, crawlable URLs.
  3. Maintain a structured heading hierarchy — card headings should logically nest under the page's section headings.
  4. Image cards should include meaningful alt text that supports image search indexing.

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 consolidates and replaces three existing AEM components:

  • Card Grid Component (#25) — grid-based card layout
  • Container with Card Style (#28) — container with card visual treatment
  • Multi Tile Listing (#43) — tile-based content listing

AEM triage

Rebuild Rebuild to new brand standards. Consolidate three legacy components into a single, token-driven card component.

Proxy / extend guidance

Create a proxy component at /apps/caat/components/card that extends the AEM Core Teaser v2 (core/wcm/components/teaser/v2/teaser). Override teaser.html to emit the CAAT class names, semantic <article> wrapper, and data attributes.

Client library structure

  • Category: caat.components.card
  • Dependencies: caat.base (tokens + base styles)
  • CSS: card.css
  • JS: card.js (analytics wiring, impression observer)

Suggested file structure

card/
├── _cq_dialog/
│   └── .content.xml          # Touch UI dialog
├── _cq_editConfig.xml         # Edit configuration
├── .content.xml                # Component node definition
├── card.html                   # HTL template
├── clientlibs/
│   ├── .content.xml
│   ├── css/
│   │   └── card.css
│   └── js/
│       └── card.js
└── README.md                   # Dev notes

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/components/card — 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:

          # ── Content tab ──────────────────────────────
          content:
            jcr:title: Content
            items:
              heading:
                sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                name: ./heading
                fieldLabel: Heading
                required: true
                maxlength: 80
              headingLevel:
                sling:resourceType: granite/ui/components/coral/foundation/form/select
                name: ./headingLevel
                fieldLabel: Heading level
                items:
                  - { text: H2, value: h2 }
                  - { text: H3, value: h3 }
                  - { text: H4, value: h4 }
              summary:
                sling:resourceType: granite/ui/components/coral/foundation/form/textarea
                name: ./summary
                fieldLabel: Summary
                maxlength: 160
              linkURL:
                sling:resourceType: granite/ui/components/coral/foundation/form/pathfield
                name: ./linkURL
                fieldLabel: Link URL
                rootPath: /content
              linkLabel:
                sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                name: ./linkLabel
                fieldLabel: Link label
              image:
                sling:resourceType: granite/ui/components/coral/foundation/form/fileupload
                name: ./image
                fieldLabel: Image
                fileReferenceParameter: ./fileReference
              imageAltText:
                sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                name: ./imageAltText
                fieldLabel: Image alt text
              kicker:
                sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                name: ./kicker
                fieldLabel: Kicker
                maxlength: 30
              icon:
                sling:resourceType: granite/ui/components/coral/foundation/form/select
                name: ./icon
                fieldLabel: Icon
                items:
                  - { text: None,     value: none }
                  - { text: People,   value: people }
                  - { text: Building, value: building }
                  - { text: Graph,    value: graph }
                  - { text: Shield,   value: shield }
                  - { text: Calendar, value: calendar }
                  - { text: Document, value: document }

          # ── Style tab ────────────────────────────────
          style:
            jcr:title: Style
            items:
              variant:
                sling:resourceType: granite/ui/components/coral/foundation/form/select
                name: ./variant
                fieldLabel: Variant
                required: true
                items:
                  - { text: Icon card,      value: icon }
                  - { text: Image card,     value: image }
                  - { text: Media overlay,  value: overlay }
                  - { text: Content card,   value: content }
              cardHeight:
                sling:resourceType: granite/ui/components/coral/foundation/form/select
                name: ./cardHeight
                fieldLabel: Card height
                items:
                  - { text: Auto,  value: auto }
                  - { text: Fixed, value: fixed }
              imageAspectRatio:
                sling:resourceType: granite/ui/components/coral/foundation/form/select
                name: ./imageAspectRatio
                fieldLabel: Image aspect ratio
                items:
                  - { text: "16:9", value: "16-9" }
                  - { text: "4:3",  value: "4-3" }
                  - { text: "1:1",  value: "1-1" }

          # ── Behaviour tab ────────────────────────────
          behaviour:
            jcr:title: Behaviour
            items:
              linkTarget:
                sling:resourceType: granite/ui/components/coral/foundation/form/checkbox
                name: ./linkTarget
                text: Open in new tab
                value: _blank
              analyticsLabel:
                sling:resourceType: granite/ui/components/coral/foundation/form/textfield
                name: ./analyticsLabel
                fieldLabel: Analytics label

13. QA Acceptance Checklist

  • All four variants (icon, image, overlay, content) render correctly with expected layout and spacing.
  • Cards display in responsive grid layouts (1-up, 2-up, 3-up, 4-up) and reflow correctly on mobile viewports.
  • Hover and focus states are visually distinct — shadow elevation and focus ring meet WCAG contrast requirements.
  • Keyboard navigation works: Tab to focus stretched-link, Enter to activate.
  • Image alt text is present on all image cards; overlay gradient provides sufficient text contrast.
  • Analytics data attributes are present in the DOM and fire the correct events on click and impression.

14. Definition of Done

AreaDone means
Design Figma component matches this contract. All variants (icon, image, overlay, content) and sizes are documented. Tokens are used — no hard-coded colour values.
Development AEM proxy component created extending Core Teaser. HTL template emits semantic HTML per Section 6. CSS uses design tokens. JS wires analytics events. 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. Legacy components (#25, #28, #43) deprecated. Content authors trained. Documentation published. Analytics dashboards confirmed receiving events.