Component Contract
Testimonials
Display member quotes and testimonials to build trust and social proof for CAAT Pension Plan.
Live Demo
Two independent axes: a layout (single · grid · carousel) and an avatar type (photo · initials · icon), with an optional star rating above any quote. Each card is a <figure>/<figcaption> composing the Avatar component.
Layout — Single · photo · with rating
"After 32 years of teaching, I retired knowing my CAAT pension would be there for me. The defined benefit plan gives me peace of mind — I never have to worry about outliving my savings."
Layout — Grid · photo
"Retiring at 60 felt like a dream, but CAAT made it a reality. My pension income replaced 70% of my working salary from day one."
"The inflation protection built into my CAAT pension means my purchasing power stays strong year after year. That's something no RRSP can guarantee."
"We partnered with CAAT five years ago. Since then, employee satisfaction scores around benefits have jumped 40%. It sells itself."
Layout — Carousel
Avatar fallbacks · initials & icon
When no photo exists, the Avatar falls back to initials, then a generic icon. The avatar type is independent of the layout.
"Joining CAAT was the best HR decision we ever made. Our employees feel secure about their future, and that shows in retention."
"The CAAT team walked us through every step of onboarding. Our staff had questions answered within days, not weeks."
1. Summary
| Component path | caat/components/testimonial |
| Status | New |
| Purpose | Display member quotes and testimonials to build trust and social proof, showcasing real experiences from CAAT pension plan members and employer partners. |
| Tier | Composite — composes Avatar |
| Variants | Layout: single · grid · carousel · Avatar: photo · initials · icon · optional star rating (independent axes) |
| Allowed on | Homepage, About, Employers, Member Stories, Landing Pages |
2. Design Tokens
| Token | Value | Usage |
|---|---|---|
--caat-color-bg-page | #fff | Card background |
--caat-color-border | grey-200 | Card border (1px, all sides) |
--caat-radius | .75rem | Card border radius |
--caat-shadow-sm | — | Card elevation |
--caat-color-text | ink | Quote text (italic, 1.1rem) |
--caat-color-text-heading / --caat-color-text-muted | blue-900 / muted | Attribution name / role |
--caat-warning | #efaa39 | Star rating |
--caat-color-action-primary / -hover | blue-900 / blue-700 | Carousel controls + indicators (hover darkens) |
| Avatar sizing/colours are inherited from the composed Avatar component (48px). | ||
3. Authoring Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Quote Text | Rich Text | Yes | The testimonial body. Supports bold/italic. Max 300 characters recommended. |
| Attribution Name | Text | Yes | Full name of the person providing the testimonial. |
| Attribution Role | Text | No | Job title or role of the quoted person (e.g., "Retired Educator"). |
| Employer Name | Text | No | Organization/employer name (e.g., "Durham College"). |
| Avatar Image | Image | No | Headshot, rendered 48×48px via the Avatar component. Falls back to initials, then a generic icon, if empty. |
| Star Rating | Number (1–5) | No | Optional star rating displayed above the quote. Omit to hide rating. |
| Display Variant | Select | Yes | Options: single | carousel | grid |
4. Validation Rules
| Field | Rule |
|---|---|
| Quote Text | Required. Non-empty. Max 500 characters. |
| Attribution Name | Required. Non-empty. Max 100 characters. |
| Avatar Image | If provided: min 128×128px, max 1 MB, formats JPG/PNG/WebP. |
| Star Rating | If provided: integer between 1 and 5 inclusive. |
| Carousel variant | Requires minimum 2 testimonial items, maximum 8. |
| Grid variant | Requires minimum 2 testimonial items, maximum 6. |
5. Content Guidance
- Authenticity: Use real quotes from real members/employers. Obtain written consent before publishing.
- Pension-relevant: Focus on retirement security, defined benefit advantages, peace of mind, inflation protection, and employer recruitment benefits.
- Length: Keep quotes concise — 1–3 sentences (under 300 characters) for maximum impact.
- Diversity: Represent a variety of roles, institutions, genders, and retirement stages.
- Attribution: Always include at minimum a name. Role and employer add credibility.
- Avoid: Specific dollar amounts, investment returns, or language that could constitute financial advice.
6. Semantic HTML
<!-- Single testimonial -->
<div class="caat-testimonial"
data-analytics-component="testimonial"
data-analytics-variant="single">
<blockquote class="caat-testimonial__quote">
<p>"Quote text here..."</p>
</blockquote>
<div class="caat-testimonial__attribution">
<img class="caat-avatar"
src="/path/to/avatar.jpg"
alt="Photo of [Name]"
width="64" height="64">
<div>
<strong>[Name]</strong><br>
<span class="text-muted">[Role] · [Employer]</span>
</div>
</div>
</div>
<!-- Carousel wrapper -->
<div class="caat-testimonial-carousel carousel slide"
data-bs-ride="false"
aria-roledescription="carousel"
aria-label="Member testimonials">
<div class="carousel-inner">
<div class="carousel-item active"
role="group"
aria-roledescription="slide"
aria-label="Testimonial 1 of N">
<!-- .caat-testimonial inside -->
</div>
</div>
<!-- prev/next controls -->
</div>
<!-- Grid wrapper -->
<div class="caat-testimonial-grid">
<!-- multiple .caat-testimonial children -->
</div>
7. CSS Contract
| Class | Element | Notes |
|---|---|---|
.caat-testimonial | Root wrapper | Single testimonial card/block. Contains quote + attribution. |
.caat-testimonial__quote | <blockquote> | Styled with left border accent, larger font, italic styling. |
.caat-avatar | Avatar | Composed component — 48px circle (photo / initials / icon). No avatar CSS in this component. |
.caat-testimonial__name / __role | Attribution | Name (heading colour, 700) / role (muted) — now used by the markup. |
.caat-testimonial__attribution | Attribution row | Flex row with avatar + name/role stack. |
.caat-testimonial-carousel | Carousel wrapper | Extends Bootstrap carousel with CAAT styling. |
.caat-testimonial-grid | Grid wrapper | CSS Grid, 1 col mobile → 2 cols tablet → 3 cols desktop. |
8. Accessibility
| Requirement | Implementation |
|---|---|
| Blockquote semantics | Use native <blockquote> element so assistive tech announces quoted text. |
| Avatar alt text | Provide descriptive alt: "Photo of [Name]". Use empty alt (alt="") if decorative. |
| Carousel — keyboard | Previous/Next buttons are keyboard-focusable. Indicators are <button> elements. |
| Carousel — pause/stop | Set data-bs-ride="false" (no autoplay). If autoplay is enabled, provide a visible Pause button. |
| Carousel — ARIA | aria-roledescription="carousel" on wrapper; aria-roledescription="slide" + aria-label on each item. |
| Reduced motion | @media (prefers-reduced-motion: reduce) disables carousel transitions and any fade animations. |
| Color contrast | Quote text and attribution meet WCAG 2.1 AA (4.5:1 minimum). |
| Star rating | If present, include visually hidden text: "Rated X out of 5 stars" for screen readers. |
9. SEO
- Testimonials may optionally emit Schema.org Review structured data (
@type: Review,author,reviewBody). - Ensure quote text is rendered in the DOM (not injected via JS) for crawlability.
- Use semantic
<blockquote>— search engines treat these as quoted content. - Avatar images should have descriptive
altattributes that include the person's name.
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 Implementation Notes
- Resource type:
caat/components/testimonial - Sling Model:
com.caat.core.models.Testimonial— exposes quote, attribution, avatar, rating, variant. - Multifield: Carousel and Grid variants use an AEM Multifield to allow authors to add 2–8 testimonial items.
- Content Fragment support: Optionally bind to a CF model
caat/models/testimonialfor headless delivery. - Policies: Restrict display variant options per template (e.g., only "grid" on homepage).
- Experience Fragment: Component can be placed in XF for shared testimonial blocks across pages.
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",
"jcr:title": "Testimonial",
"content": {
"items": {
"tabs": {
"items": {
"testimonialTab": {
"jcr:title": "Testimonial",
"items": {
"variant": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/select",
"fieldLabel": "Display Variant",
"name": "./variant",
"required": true,
"options": ["single", "carousel", "grid"]
},
"testimonials": {
"sling:resourceType": "granite/ui/components/coral/foundation/form/multifield",
"fieldLabel": "Testimonials",
"composite": true,
"items": {
"quoteText": { "sling:resourceType": "cq/gui/components/authoring/dialog/richtext", "fieldLabel": "Quote", "name": "./quoteText" },
"attributionName": { "sling:resourceType": "granite/ui/components/coral/foundation/form/textfield", "fieldLabel": "Name", "name": "./attributionName", "required": true },
"attributionRole": { "sling:resourceType": "granite/ui/components/coral/foundation/form/textfield", "fieldLabel": "Role", "name": "./attributionRole" },
"employerName": { "sling:resourceType": "granite/ui/components/coral/foundation/form/textfield", "fieldLabel": "Employer", "name": "./employerName" },
"avatarImage": { "sling:resourceType": "cq/gui/components/authoring/dialog/fileupload", "fieldLabel": "Avatar", "name": "./avatarImage" },
"starRating": { "sling:resourceType": "granite/ui/components/coral/foundation/form/numberfield", "fieldLabel": "Rating (1-5)", "name": "./starRating", "min": 1, "max": 5 }
}
}
}
}
}
}
}
}
}
13. QA Acceptance Checklist
- All three variants (single, carousel, grid) render correctly.
- Blockquote semantic HTML is present in DOM.
- Avatar falls back gracefully when no image is provided.
- Carousel: prev/next/indicator buttons work via keyboard.
- Carousel does NOT autoplay by default.
- Reduced-motion media query disables transitions.
- Grid is responsive: 1 col → 2 cols → 3 cols.
- Star rating (if present) has visually hidden accessible text.
- Analytics events fire:
testimonial-viewed,carousel-interaction. - Cross-browser tested (Chrome, Firefox, Safari, Edge).
- Content contrast meets WCAG 2.1 AA (4.5:1 for text).
14. Definition of Done
| Area | Done means |
|---|---|
| Design | Figma component matches this contract. All three variants are documented. Tokens are used — no hard-coded colour values. |
| Development | AEM proxy component created under caat/components/testimonial. 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. |
| Launch | Component deployed to AEM production. Content authors trained. Documentation published. Analytics dashboards confirmed receiving events. |