Component Contract
Image / Embed
Responsive images, video embeds, and media containers for the CAAT Pension Plan member experience.
Live Demo
Responsive Image with Caption
Rendered
Image with Aspect Ratios
Rendered
16:9
4:3
1:1
3:2
4:5
Video Embed (16:9)
Vimeo
Rendered
YouTube
Rendered
Decorative vs Informative Image
Rendered
Decorative alt=""
Informative alt="…"
Code sample
HTML
<!-- Responsive image with caption -->
<div class="caat-image">
<figure class="caat-image__figure">
<img class="caat-image__img"
src="photo.jpg"
alt="Descriptive alt text for screen readers">
<figcaption class="caat-image__caption">Caption text here.</figcaption>
</figure>
</div>
<!-- Aspect ratio container (16:9) -->
<div class="caat-image caat-image--16-9">
<img class="caat-image__img" src="photo.jpg" alt="Description">
</div>
<!-- Vimeo embed (responsive 16:9) -->
<div class="caat-embed">
<div class="caat-embed__wrapper">
<iframe class="caat-embed__iframe"
src="https://player.vimeo.com/video/VIDEO_ID?h=HASH&title=0&byline=0&portrait=0&texttrack=en"
title="Video title for accessibility"
allow="autoplay; fullscreen; picture-in-picture"
allowfullscreen></iframe>
</div>
</div>
<!-- YouTube embed (responsive 16:9) -->
<div class="caat-embed">
<div class="caat-embed__wrapper">
<iframe class="caat-embed__iframe"
src="https://www.youtube.com/embed/VIDEO_ID?rel=0"
title="Video title for accessibility"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
</div>
<!-- Decorative image (empty alt) -->
<img class="caat-image__img" src="decorative.jpg" alt="" role="presentation">
<!-- Informative image (descriptive alt) -->
<img class="caat-image__img" src="chart.jpg" alt="Bar chart showing pension fund growth from 2020 to 2025">
1. Summary
| Component | Image / Embed |
| AEM Resource Type | caat/components/image-embed |
| Purpose | Displays responsive images, video embeds, and media containers with consistent styling, aspect-ratio enforcement, and accessibility compliance. |
| Variants | Responsive image with caption · Aspect-ratio constrained (16:9, 4:3, 1:1) · Video embed (16:9 iframe) · Decorative / Informative |
| Contains | Image element, optional figure/figcaption, embed wrapper, iframe |
| Used in | Article pages, hero sections, blog posts, landing pages, member communications |
| Figma | CAAT DS / Components / Image-Embed |
| Status | Enhance |
2. Design Tokens
| Token | Role | Value (light) |
|---|---|---|
--caat-blue-900 | Link/overlay text colour | #003750 |
--caat-blue-700 | Hover accent | #0b5a80 |
--caat-blue-100 | Light background tint | #e7f4fb |
--caat-green | Success indicator | #55a546 |
--caat-grey-200 | Embed placeholder background | #dfe6ef |
--caat-focus | Focus ring on interactive media | #4D90FE |
--caat-ink | Caption text colour | #102637 |
--caat-radius | Border-radius for images and embeds | .75rem |
--caat-font-primary | Font family | Libre Franklin |
3. Authoring Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Variant | Select | Yes | image | embed |
| Image asset | Asset picker | Yes (image) | DAM reference path. Supports JPEG, PNG, WebP, SVG. |
| Alt text | Text | Conditional | Required for informative images. Leave empty for decorative images (author must confirm decorative intent). |
| Caption | Text | No | Optional figure caption displayed below the image. |
| Aspect ratio | Select | No | auto | 16:9 | 4:3 | 1:1. Default: auto (intrinsic ratio). |
| Decorative | Toggle | No | When enabled, renders empty alt="" and role="presentation". |
| Embed URL | URL | Yes (embed) | YouTube or Vimeo embed URL. Must be HTTPS. |
| Embed title | Text | Yes (embed) | Accessible title for the iframe. |
| Lazy load | Toggle | No | Adds loading="lazy" attribute. Default: enabled. |
4. Validation
| Rule | Error message |
|---|---|
| Image asset is required for image variant. | "Select an image from the DAM." |
| Alt text required unless Decorative is toggled. | "Provide alt text or mark the image as decorative." |
| Embed URL is required for embed variant. | "Enter a valid embed URL." |
| Embed URL must be HTTPS. | "Embed URL must use HTTPS." |
| Embed title is required. | "Provide a title for the embedded content." |
| Alt text must not exceed 125 characters. | "Alt text should be concise (125 characters max)." |
5. Content Guidance
- Alt text should describe the content and function of the image, not its appearance: "Chart showing 12% pension growth" not "a bar chart".
- Use decorative mode only for purely ornamental images (backgrounds, separators, abstract textures).
- Captions provide supplementary context — do not duplicate alt text in the caption.
- For video embeds, always provide a descriptive title: "2025 CAAT Annual Report Summary".
- Prefer WebP format for performance; provide JPEG/PNG fallback via AEM renditions.
- Use aspect-ratio constraints when images must align in a grid layout.
- Keep embed URLs pointed to the embed endpoint (e.g.,
youtube.com/embed/…), not the watch URL.
6. Semantic HTML
Informative image with caption
<div class="caat-image">
<figure class="caat-image__figure">
<img class="caat-image__img"
src="/content/dam/caat/images/photo.jpg"
alt="Descriptive text about image content"
loading="lazy">
<figcaption class="caat-image__caption">Caption text.</figcaption>
</figure>
</div>
Decorative image
<div class="caat-image">
<img class="caat-image__img"
src="/content/dam/caat/images/decorative.jpg"
alt=""
role="presentation"
loading="lazy">
</div>
Video embed
<div class="caat-embed">
<div class="caat-embed__wrapper">
<iframe class="caat-embed__iframe"
src="https://www.youtube.com/embed/VIDEO_ID"
title="Accessible video title"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
loading="lazy"></iframe>
</div>
</div>
7. CSS Contract
| Selector | Purpose |
|---|---|
.caat-image | Image block container. |
.caat-image__figure | Semantic figure wrapper (resets margin). |
.caat-image__img | Image element. Full width, auto height, border-radius, display block. |
.caat-image__caption | Figcaption. Muted text, small font, padding-top. |
.caat-image--16-9 | Aspect-ratio 16/9 container with overflow hidden. |
.caat-image--4-3 | Aspect-ratio 4/3 container with overflow hidden. |
.caat-image--1-1 | Aspect-ratio 1/1 container with overflow hidden. |
.caat-image--3-2 | Aspect-ratio 3/2 container (editorial photography). |
.caat-image--4-5 | Aspect-ratio 4/5 container (editorial portrait). |
.caat-embed | Embed block container. |
.caat-embed__wrapper | Responsive 16:9 wrapper using aspect-ratio CSS property. Overflow hidden, border-radius. |
.caat-embed__iframe | Iframe. 100% width and height, no border. |
8. Accessibility
| Requirement | Implementation |
|---|---|
| Informative images | Meaningful alt text describing content and function (max 125 chars). |
| Decorative images | Empty alt="" plus role="presentation" to hide from assistive tech. |
| Iframe title | All iframes require a title attribute describing the embedded content. |
| Keyboard access | Embedded media must be focusable and operable via keyboard. |
| Captions / transcripts | Videos must have captions. A transcript link should be provided where possible. |
| Reduced motion | Autoplay videos must respect prefers-reduced-motion. |
| Colour contrast | Caption text meets WCAG 2.1 AA 4.5:1 contrast ratio. |
| Focus indicator | Interactive embeds show visible :focus-visible ring using --caat-focus. |
9. SEO
- Use descriptive, keyword-rich alt text for informative images — aids Google Image Search indexing.
- Use semantic
<figure>/<figcaption>elements to associate captions with images. - Filename should be human-readable:
pension-growth-chart-2025.webpnotIMG_4521.jpg. - Include
loading="lazy"on below-fold images to improve Core Web Vitals (LCP). - Use structured data (
ImageObject) for key images when applicable. - Embeds are not indexable — provide surrounding text context and a transcript for videos.
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/image-embed - Sling Model:
ImageEmbedModel— exposessrc,alt,caption,aspectRatio,decorative,embedUrl,embedTitle,lazyLoad. - HTL template:
image-embed.html— usesdata-sly-testto switch between image and embed variants. - Renditions: AEM generates responsive renditions (320w, 640w, 960w, 1280w). Uses
srcsetandsizesfor art direction. - Client library:
caat.components.image-embed— CSS only; optional JS for lazy-loading polyfill and analytics. - Policy: Authors can restrict allowed aspect ratios and embed domains per template policy.
- Allowed parents: Layout Container, Article Body, Card Body, Hero.
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).
{
"jcr:primaryType": "nt:unstructured",
"sling:resourceType": "cq/gui/components/authoring/dialog",
"tabs": {
"properties": {
"variant": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/select",
"label": "Variant",
"name": "./variant",
"required": true,
"options": ["image", "embed"]
},
"imageAsset": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/pathfield",
"label": "Image asset",
"name": "./fileReference",
"rootPath": "/content/dam/caat",
"required": true
},
"altText": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/textfield",
"label": "Alt text",
"name": "./alt",
"maxlength": 125
},
"caption": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/textfield",
"label": "Caption",
"name": "./caption"
},
"aspectRatio": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/select",
"label": "Aspect ratio",
"name": "./aspectRatio",
"options": ["auto", "16:9", "4:3", "1:1"]
},
"decorative": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/checkbox",
"label": "Decorative image",
"name": "./decorative"
},
"embedUrl": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/textfield",
"label": "Embed URL",
"name": "./embedUrl"
},
"embedTitle": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/textfield",
"label": "Embed title",
"name": "./embedTitle"
},
"lazyLoad": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/checkbox",
"label": "Lazy load",
"name": "./lazyLoad",
"checked": true
}
}
}
}
13. QA Acceptance Checklist
- Responsive image scales to 100% container width without distortion.
- Caption renders below the image with correct muted styling.
- Aspect-ratio containers (16:9, 4:3, 1:1) crop images correctly with object-fit: cover.
- Video embed wrapper maintains 16:9 ratio at all viewport sizes.
- Decorative images render with empty
alt=""androle="presentation". - Informative images have descriptive alt text announced by screen readers.
- Iframe has
titleattribute readable by assistive technology. - Images have
loading="lazy"when below the fold. - Border-radius applies consistently across image and embed variants.
- Focus ring visible on interactive embeds during keyboard navigation.
- Analytics events (
image-viewed,embed-play) fire correctly. - Cross-browser tested: Chrome, Firefox, Safari, Edge.
- Mobile: images and embeds render correctly at 320px viewport.
14. Definition of Done
| Area | Done means |
|---|---|
| Design | Figma component matches this contract. All aspect-ratio variants and embed wrapper documented. Decorative vs informative patterns illustrated. |
| Development | AEM proxy component created. HTL template emits semantic HTML per Section 6. CSS uses design tokens exclusively. Alt text and iframe title wired. Responsive renditions configured. 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 alt text requirements and decorative toggle. Documentation published. Analytics dashboards confirmed receiving events. |