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.

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 namecaat/components/list-group
PurposeFlexible 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
VariantsBasic, Actionable (links/buttons), Badge, Icon with secondary text, Flush
OptionsActive item highlight, flush mode (no outer border), badge counter, leading icon, secondary description text
AEM resource typecaat/components/list-group
AEM categoryCAAT Components – Lists

2. Design Tokens

List groups consume these semantic tokens — no component-specific tokens are defined.

TokenRole
--caat-color-bg-pageItem background
--caat-color-textItem text colour
--caat-color-text-mutedSecondary item text
--caat-color-borderBorder between items
--caat-color-state-hover-bgActionable item hover background
--caat-color-state-selected-bg / -selected-textActive / current item background + text
--caat-color-text-linkActionable item link text
--caat-color-bg-brand / --caat-color-text-inverseBadge counter background + text
--caat-radiusOuter border radius
--caat-font-primaryFont family

3. Authoring Fields

FieldTypeRequiredNotes
ItemsMultifieldYes1–20 items. Each item contains the sub-fields below.
  ↳ LabelText fieldYesPrimary text displayed in the list item. Max 120 characters.
  ↳ DescriptionText fieldNoSecondary text rendered below the label in smaller, muted type. Max 200 characters.
  ↳ URLPath browserNoWhen provided, the item renders as an actionable link (<a>). Supports internal AEM paths and external URLs.
  ↳ Badge TextText fieldNoShort counter or label displayed as a pill badge on the right side. Max 10 characters.
  ↳ IconIcon pickerNoBootstrap Icon class placed before the label (e.g., bi-file-earmark-pdf).
VariantDropdown (default | flush)NoDefault: "default". Flush removes the outer border and border-radius for embedding inside cards.
Active Item IndexNumberNo1-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

GuidelineDetail
ToneClear, concise labels that describe the content or action. Use sentence case.
Resource listsUse icons and descriptions for document downloads (PDF, XLSX). Include file size and date in the description.
Task listsUse actionable items (links) with verb-first labels: "View my statement", "Update beneficiary info".
Notification listsPair items with badge counters. Include visually hidden context for screen readers (e.g., "3 new statements").
Flush variantUse when embedding a list group inside a card or panel — removes redundant outer borders.
Active itemUse to indicate the currently selected or viewed item (e.g., current page in a resource list).
Don'tDon'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 with role="list" and role="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

SelectorPurpose
.caat-list-groupBase wrapper — resets list style, applies outer border-radius and overflow hidden.
.caat-list-group__itemIndividual list item — padding, border-bottom, background.
.caat-list-group__item--activeActive/selected state — CAAT blue-900 background, white text, matching border colour.
.caat-list-group__item--actionActionable item modifier — adds hover/focus background, pointer cursor, action text colour.
.caat-list-group__badgeInline pill badge — counter background, white text, border-radius 50rem.
.caat-list-group--flushFlush 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

RequirementImplementation
List semanticsNon-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 itemThe currently selected item uses aria-current="true" so screen readers announce it as the current item.
Badge contextBadge counters include a <span class="visually-hidden"> providing full context (e.g., "3 new statements" instead of just "3").
Colour contrastAll item text, active state, and badge text meets WCAG 2.1 AA (4.5:1 minimum contrast ratio).
Keyboard navigationActionable items are focusable via Tab key. Focus styles are visible and use the standard CAAT focus ring.
Decorative iconsIcons use aria-hidden="true" because the label text already provides meaning.
Reduced motionHover/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 — exposes items (list of ListGroupItemModel), variant, activeIndex.
  • ListGroupItemModel: Exposes label, description, url, badgeText, icon.
  • HTL: list-group.html — uses data-sly-list over 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" and role="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

AreaDone 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.