Component Contract
List Group
Flexible list of content items with optional actions, badges, and icons — for resource lists, task lists, and document downloads across CAAT digital properties.
Live Demo
Basic List Group — Pension Resources
Rendered
- Understanding your DBplus pension
- Contribution rates & schedules
- Retirement income estimator
- Survivor benefit options
- Pension inflation protection
Actionable List Group — Member Dashboard
List Group with Badges — Notifications
Rendered
- Pension statements 3 new statements
- Secure messages 12 unread messages
- Action items 1 pending action
- Plan updates 5 new updates
List Group with Icons & Secondary Text
Rendered
-
2025 Annual Pension Statement
PDF · 245 KB · Updated Jan 15, 2026
-
Contribution History Export
XLSX · 128 KB · Updated Feb 1, 2026
-
DBplus Plan Summary
PDF · 1.2 MB · Updated Mar 10, 2026
-
Retirement Income Estimator Tool
Interactive tool · Last accessed Apr 22, 2026
Flush Variant — Embedded in Card
States
Follows the Interaction States matrix. Actionable items implement default, hover, focus, and active (current/selected). The static is-* classes mirror the live pseudo-class states.
Rendered
Code sample
HTML
<!-- Basic list group -->
<ul class="caat-list-group">
<li class="caat-list-group__item">Understanding your DBplus pension</li>
<li class="caat-list-group__item caat-list-group__item--active" aria-current="true">Contribution rates</li>
<li class="caat-list-group__item">Retirement income estimator</li>
</ul>
<!-- Actionable list group -->
<div class="caat-list-group" role="list">
<a href="/statements" class="caat-list-group__item caat-list-group__item--action" role="listitem">
View my pension statement
</a>
</div>
<!-- List group with badge -->
<ul class="caat-list-group">
<li class="caat-list-group__item d-flex justify-content-between align-items-center">
Secure messages
<span class="caat-list-group__badge">12
<span class="visually-hidden"> unread messages</span>
</span>
</li>
</ul>
<!-- Flush variant (no outer border) -->
<ul class="caat-list-group caat-list-group--flush">
<li class="caat-list-group__item">Item one</li>
</ul>
1. Summary
| Component name | caat/components/list-group |
| Purpose | Flexible list of content items with optional actions, badges, and icons. Used for resource lists, task lists, document downloads, member dashboard quick links, and notification summaries across CAAT digital properties. |
| Status | New |
| Variants | Basic, Actionable (links/buttons), Badge, Icon with secondary text, Flush |
| Options | Active item highlight, flush mode (no outer border), badge counter, leading icon, secondary description text |
| AEM resource type | caat/components/list-group |
| AEM category | CAAT Components – Lists |
2. Design Tokens
List groups consume these semantic tokens — no component-specific tokens are defined.
| Token | Role |
|---|---|
--caat-color-bg-page | Item background |
--caat-color-text | Item text colour |
--caat-color-text-muted | Secondary item text |
--caat-color-border | Border between items |
--caat-color-state-hover-bg | Actionable item hover background |
--caat-color-state-selected-bg / -selected-text | Active / current item background + text |
--caat-color-text-link | Actionable item link text |
--caat-color-bg-brand / --caat-color-text-inverse | Badge counter background + text |
--caat-radius | Outer border radius |
--caat-font-primary | Font family |
3. Authoring Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Items | Multifield | Yes | 1–20 items. Each item contains the sub-fields below. |
| ↳ Label | Text field | Yes | Primary text displayed in the list item. Max 120 characters. |
| ↳ Description | Text field | No | Secondary text rendered below the label in smaller, muted type. Max 200 characters. |
| ↳ URL | Path browser | No | When provided, the item renders as an actionable link (<a>). Supports internal AEM paths and external URLs. |
| ↳ Badge Text | Text field | No | Short counter or label displayed as a pill badge on the right side. Max 10 characters. |
| ↳ Icon | Icon picker | No | Bootstrap Icon class placed before the label (e.g., bi-file-earmark-pdf). |
| Variant | Dropdown (default | flush) | No | Default: "default". Flush removes the outer border and border-radius for embedding inside cards. |
| Active Item Index | Number | No | 1-based index of the item to highlight as active. Sets aria-current="true". |
4. Validation Rules
- At least one item is required; component will not render without it.
- Each item must have a Label; items without labels are skipped at render time.
- Label max length: 120 characters. Exceeding triggers an author-facing warning.
- Description max length: 200 characters.
- Badge text max length: 10 characters (intended for short counters or labels).
- Maximum 20 items per list group. Exceeding triggers a validation error.
- Active Item Index must be between 1 and the total number of items, or left empty.
- If any item has a URL, it renders as an
<a>; items without URLs render as non-interactive<li>elements.
5. Content Guidance
| Guideline | Detail |
|---|---|
| Tone | Clear, concise labels that describe the content or action. Use sentence case. |
| Resource lists | Use icons and descriptions for document downloads (PDF, XLSX). Include file size and date in the description. |
| Task lists | Use actionable items (links) with verb-first labels: "View my statement", "Update beneficiary info". |
| Notification lists | Pair items with badge counters. Include visually hidden context for screen readers (e.g., "3 new statements"). |
| Flush variant | Use when embedding a list group inside a card or panel — removes redundant outer borders. |
| Active item | Use to indicate the currently selected or viewed item (e.g., current page in a resource list). |
| Don't | Don't mix actionable and non-actionable items in the same list. Don't exceed 20 items — consider pagination or filtering. |
6. Semantic HTML
HTL / Markup contract
<!-- Basic list group (non-interactive) -->
<ul class="caat-list-group">
<li class="caat-list-group__item">{label}</li>
<li class="caat-list-group__item caat-list-group__item--active" aria-current="true">{activeLabel}</li>
</ul>
<!-- Actionable list group (links) -->
<div class="caat-list-group" role="list">
<a href="{url}" class="caat-list-group__item caat-list-group__item--action" role="listitem">
{label}
</a>
</div>
<!-- Item with badge -->
<li class="caat-list-group__item d-flex justify-content-between align-items-center">
{label}
<span class="caat-list-group__badge">{count}
<span class="visually-hidden">{hiddenContext}</span>
</span>
</li>
<!-- Item with icon and description -->
<li class="caat-list-group__item">
<div class="d-flex align-items-start">
<i class="bi bi-{icon} me-3 fs-4" aria-hidden="true"></i>
<div>
<strong>{label}</strong>
<p class="mb-0 small text-muted">{description}</p>
</div>
</div>
</li>
<!-- Flush variant -->
<ul class="caat-list-group caat-list-group--flush">
<li class="caat-list-group__item">{label}</li>
</ul>
Key decisions
<ul>with<li>is used for non-interactive lists, preserving native list semantics.- For actionable lists composed of
<a>elements, a<div>wrapper withrole="list"androle="listitem"on each child maintains list semantics for assistive technology. - Active items use
aria-current="true"to indicate the currently selected item to screen readers. - Icons use
aria-hidden="true"because the label text already conveys meaning. - Badge counters include a
<span class="visually-hidden">to provide full context for screen readers.
7. CSS Contract
| Selector | Purpose |
|---|---|
.caat-list-group | Base wrapper — resets list style, applies outer border-radius and overflow hidden. |
.caat-list-group__item | Individual list item — padding, border-bottom, background. |
.caat-list-group__item--active | Active/selected state — CAAT blue-900 background, white text, matching border colour. |
.caat-list-group__item--action | Actionable item modifier — adds hover/focus background, pointer cursor, action text colour. |
.caat-list-group__badge | Inline pill badge — counter background, white text, border-radius 50rem. |
.caat-list-group--flush | Flush modifier — removes outer border-radius and left/right borders for embedding in cards. |
Sample CSS
.caat-list-group {
display: flex;
flex-direction: column;
padding-left: 0;
margin-bottom: 0;
list-style: none;
border-radius: var(--caat-list-group-border-radius);
overflow: hidden;
border: var(--caat-list-group-border-width) solid var(--caat-list-group-border-color);
}
.caat-list-group__item {
position: relative;
display: block;
padding: var(--caat-list-group-padding-y) var(--caat-list-group-padding-x);
background-color: var(--caat-list-group-bg);
color: var(--caat-list-group-color);
border-bottom: var(--caat-list-group-border-width) solid var(--caat-list-group-border-color);
text-decoration: none;
}
.caat-list-group__item:last-child {
border-bottom: 0;
}
.caat-list-group__item--active {
background-color: var(--caat-list-group-active-bg);
color: var(--caat-list-group-active-color);
border-color: var(--caat-list-group-active-border);
z-index: 2;
}
.caat-list-group__item--action {
color: var(--caat-list-group-action-color);
cursor: pointer;
}
.caat-list-group__item--action:hover,
.caat-list-group__item--action:focus {
background-color: var(--caat-list-group-hover-bg);
text-decoration: none;
}
.caat-list-group__badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 1.5rem;
padding: 0.25em 0.65em;
font-size: 0.75em;
font-weight: 700;
line-height: 1;
background-color: var(--caat-list-group-badge-bg);
color: var(--caat-list-group-badge-color);
border-radius: var(--caat-list-group-badge-radius);
}
.caat-list-group--flush {
border-radius: 0;
border-left: 0;
border-right: 0;
}
.caat-list-group--flush .caat-list-group__item:first-child {
border-top: 0;
}
.caat-list-group--flush .caat-list-group__item:last-child {
border-bottom: 0;
}
8. Accessibility
| Requirement | Implementation |
|---|---|
| List semantics | Non-interactive lists use <ul>/<ol> with <li>. Actionable lists use <div role="list"> with <a role="listitem"> to preserve list semantics for screen readers. |
| Active item | The currently selected item uses aria-current="true" so screen readers announce it as the current item. |
| Badge context | Badge counters include a <span class="visually-hidden"> providing full context (e.g., "3 new statements" instead of just "3"). |
| Colour contrast | All item text, active state, and badge text meets WCAG 2.1 AA (4.5:1 minimum contrast ratio). |
| Keyboard navigation | Actionable items are focusable via Tab key. Focus styles are visible and use the standard CAAT focus ring. |
| Decorative icons | Icons use aria-hidden="true" because the label text already provides meaning. |
| Reduced motion | Hover/focus transitions respect prefers-reduced-motion: reduce. |
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/list-group - Component group: CAAT Components – Lists
- Proxy: Create as a proxy component under
/apps/caat/components/list-group. - Policies: Configure maximum item count and allowed icon set per template via content policies.
- Sling Model:
com.caat.core.models.ListGroupModel— exposesitems(list ofListGroupItemModel),variant,activeIndex. - ListGroupItemModel: Exposes
label,description,url,badgeText,icon. - HTL:
list-group.html— usesdata-sly-listover items multifield. Conditionally renders<a>vs<li>based on URL presence. - Client library:
caat.components.list-group(categories:caat.site). - Style System: Flush variant available via style tab for card-embedded use cases.
12. Dialog Model (YAML)
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: List Group
description: Flexible list of content items with optional actions, badges, and icons.
fields:
- name: items
label: Items
type: multifield
required: true
minItems: 1
maxItems: 20
helpText: Add between 1 and 20 list items.
fields:
- name: label
label: Label
type: textfield
required: true
maxLength: 120
helpText: Primary text for this list item.
- name: description
label: Description
type: textfield
required: false
maxLength: 200
helpText: Optional secondary text displayed below the label.
- name: url
label: URL
type: pathbrowser
required: false
helpText: Link target. When provided, item renders as an actionable link.
- name: badgeText
label: Badge Text
type: textfield
required: false
maxLength: 10
helpText: Short counter or label displayed as a pill badge (e.g., "3", "New").
- name: icon
label: Icon
type: iconpicker
required: false
helpText: Bootstrap Icon displayed before the label (e.g., bi-file-earmark-pdf).
- name: variant
label: Variant
type: select
required: false
options:
- value: default
label: Default (bordered)
- value: flush
label: Flush (no outer border)
helpText: Flush variant removes outer borders for embedding in cards.
- name: activeIndex
label: Active Item Index
type: number
required: false
min: 1
helpText: 1-based index of the item to highlight as active/current.
13. QA Acceptance Checklist
- Basic list group renders as
<ul>with proper<li>semantics. - Actionable list group renders links with
role="list"androle="listitem". - Active item displays CAAT blue-900 background with white text and
aria-current="true". - Badge counters render as pill shapes with correct background and visually hidden context.
- Icons render before labels with
aria-hidden="true". - Description text renders below labels in muted, smaller type.
- Flush variant removes outer border-radius and left/right borders.
- Hover/focus states visible on actionable items with correct background colour.
- Keyboard Tab navigation reaches all actionable items with visible focus ring.
- Colour contrast meets WCAG 2.1 AA (4.5:1) for all states (default, active, hover).
- Component does not render when items multifield is empty.
- Analytics events (
list-group-displayed,list-group-item-click) fire with expected data attributes. - Cross-browser tested: Chrome, Firefox, Safari, Edge.
14. Definition of Done
| Area | Done means |
|---|---|
| Design | Figma component matches this contract. All five variants (Basic, Actionable, Badge, Icon + description, Flush) documented. Active/hover/focus states specified with design tokens. |
| Development | AEM proxy component created. HTL template emits semantic HTML per Section 6. CSS uses design tokens exclusively. Multifield dialog wired with validation. Unit tests pass. |
| QA | All items in the QA Acceptance Checklist (Section 13) pass. Manual accessibility audit completed. Screen reader testing (NVDA, VoiceOver) confirms list semantics and aria-current. Cross-browser tested. |
| Launch | Component deployed to AEM production. Content authors trained on items multifield, badge usage, and flush variant for card embedding. Documentation published. Analytics dashboards confirmed. |