Component Contract
Badge
Small label or counter used for categorization, status indicators, and notification counts across the CAAT Pension Plan member experience.
Live Demo
Colour Badges
Rendered
Pill Badges
Rendered
Soft Pill Badges (category labels on cards)
Rendered
Badge on Button
Rendered
Status Badges (Member Dashboard)
Rendered
Code sample
HTML
<!-- Colour badge -->
<span class="caat-badge caat-badge--primary">Primary</span>
<!-- Pill badge -->
<span class="caat-badge caat-badge--secondary caat-badge--pill">DBprime</span>
<!-- Badge on button with visually-hidden context -->
<button type="button" class="btn btn-primary position-relative">
Messages
<span class="caat-badge caat-badge--danger caat-badge--pill
position-absolute top-0 start-100 translate-middle">
4
<span class="visually-hidden">unread messages</span>
</span>
</button>
<!-- Status badge with icon -->
<span class="caat-badge caat-badge--success caat-badge--pill">
<i class="bi bi-check-circle-fill me-1" aria-hidden="true"></i>Active
</span>
1. Summary
| Component name | caat/components/badge |
| Purpose | Small label or counter used for categorization, status indicators, and notification counts. Used on member dashboards, contribution tables, and notification centres to convey membership status, plan type, or unread item counts. |
| Status | Active |
| Variants | Primary, Secondary, Info, Warning, Danger, Light, Dark, Outline, Soft Blue, Soft Green, Soft Teal, Soft Warning, Soft Danger, Active, Pending, Retired |
| Options | Pill shape toggle, optional leading icon |
| AEM resource type | caat/components/badge |
| AEM category | CAAT Components – Indicators |
2. Design Tokens
| Token / Value | Role | Resolved Value |
|---|---|---|
--caat-blue-900 | Primary background | #003750 |
--caat-green-700 | Secondary background | #367f32 |
--caat-info | Info background | #0dcaf0 |
--caat-warning | Warning background | #efaa39 |
--caat-danger | Danger background | #b83232 |
--caat-grey | Light background | #eff2f7 |
--caat-ink | Dark background / dark text colour | #102637 |
--caat-grey-200 | Outline border / Light border | #dfe6ef |
--caat-blue-100 | Soft blue background / Retired background | #e7f4fb |
--caat-green-100 | Soft green background | #e8f5e6 |
--caat-green-900 | Soft green text | #204b1f |
--caat-warning-bg | Soft warning / Pending background | #fff3cd |
--caat-warning-text | Soft warning / Pending text | #664d03 |
--caat-danger-bg | Soft danger background | #fde8e8 |
--caat-danger-accent | Soft danger text | #c0392b |
--caat-success-bg | Active status background | #d1e7dd |
--caat-success-text | Active status text | #0a3622 |
| (hardcoded) | Soft teal background | #e4f7f8 |
| (hardcoded) | Soft teal text | #0a7a86 |
3. Authoring Fields
| Field | Type | Required | Notes |
|---|---|---|---|
| Text | Text field | Yes | The visible badge label. Max 30 characters. Examples: "Active", "DBplus", "4". |
| Variant | Dropdown (primary | secondary | success | info | warning | danger | light | dark) | Yes | Determines colour scheme. Primary maps to CAAT blue-900; secondary to CAAT green. |
| Pill | Toggle (boolean) | No | Default: off. When enabled, applies fully rounded corners (caat-badge--pill). |
| Visually Hidden Context | Text field | No | Screen-reader-only text appended after the badge label (e.g., "unread messages"). Required when badge conveys meaning beyond decoration. |
| Icon | Icon picker | No | Optional Bootstrap Icon placed before the label text (e.g., bi-check-circle-fill for status badges). |
4. Validation Rules
- Text is mandatory; component will not render without it.
- Text max length: 30 characters. Exceeding triggers an author-facing warning.
- Variant is required; defaults to "primary" if not explicitly set.
- When badge is used as a notification counter on a button, Visually Hidden Context is required (e.g., "unread messages").
- If the badge conveys status meaning (Active, Pending, Retired), Visually Hidden Context should describe the status in full (e.g., "membership status: active").
5. Content Guidance
| Guideline | Detail |
|---|---|
| Tone | Short, factual labels. One or two words maximum for text badges; numerals only for counters. |
| Use Primary for | Plan identifiers — "DBplus", "DBprime". Default categorization labels. |
| Use Secondary for | Supplementary categories — employer type, contribution tier. |
| Use Success for | Positive statuses — "Active", "Enrolled", "Confirmed". |
| Use Warning for | Pending states — "Pending", "Review Required", "Expiring Soon". |
| Use Danger for | Urgent indicators — notification counts, "Overdue", "Action Required". |
| Use Info for | Neutral informational labels — "New", "Updated", "Beta". |
| Use Soft variants for | Category pills on blog/resource cards — Soft Blue for pension news, Soft Green for employer content, Soft Teal for investment topics. |
| Use Status badges for | Member dashboard — Active (enrolled), Pending (awaiting action), Retired (former member). Always shown as pills. |
| Use Outline for | Subtle, non-coloured category labels on cards where a softer visual treatment is needed. |
| Pill shape | Preferred for status indicators, category labels on cards, and notification counters. Use standard (rectangular) for inline categorical labels. |
| Don't | Use badges for long text. Don't rely on colour alone to convey meaning — always pair with descriptive text or an icon. |
6. Semantic HTML
HTL / Markup contract
<!-- Basic badge -->
<span class="caat-badge caat-badge--{variant}">
{text}
</span>
<!-- Pill badge with icon -->
<span class="caat-badge caat-badge--{variant} caat-badge--pill">
<i class="bi bi-{icon} me-1" aria-hidden="true"></i>
{text}
</span>
<!-- Counter badge on button with visually-hidden context -->
<button type="button" class="btn btn-primary position-relative">
{buttonLabel}
<span class="caat-badge caat-badge--danger caat-badge--pill
position-absolute top-0 start-100 translate-middle">
{count}
<span class="visually-hidden">{hiddenContext}</span>
</span>
</button>
<!-- Status badge -->
<span class="caat-badge caat-badge--success caat-badge--pill">
<i class="bi bi-check-circle-fill me-1" aria-hidden="true"></i>
Active
<span class="visually-hidden">membership status: active</span>
</span>
Key decisions
<span>is used (not a heading or interactive element) as badges are inline, non-interactive labels.- Icons use
aria-hidden="true"because the visible text already conveys the label meaning. <span class="visually-hidden">provides screen-reader context when the badge conveys meaning not apparent from surrounding text (e.g., notification counts).- When used inside a
<button>, Bootstrap positioning utilities overlay the badge as a counter.
7. CSS Contract
| Selector | Purpose |
|---|---|
.caat-badge | Base badge — inline-flex, font-size, padding, border-radius, font-weight 700, vertical alignment. |
.caat-badge--primary | Primary colour scheme (CAAT blue-900 background, white text). |
.caat-badge--secondary | Secondary colour scheme (CAAT green-700 background, white text). |
.caat-badge--warning | Warning colour scheme (amber background, dark text). |
.caat-badge--danger | Danger colour scheme (red background, white text). |
.caat-badge--info | Info colour scheme (cyan background, dark text). |
.caat-badge--light | Light colour scheme (light grey background, dark text). |
.caat-badge--dark | Dark colour scheme (dark background, white text). |
.caat-badge--pill | Pill modifier — applies border-radius: 50rem for fully rounded shape. |
.caat-badge--outline | Light outline style — transparent bg, grey-200 border, ink text. |
.caat-badge--soft-blue | Soft blue — blue-100 bg, blue-900 text. For category pills on cards. |
.caat-badge--soft-green | Soft green — green-100 bg, green-900 text. |
.caat-badge--soft-teal | Soft teal — light teal bg, teal-dark text. |
.caat-badge--soft-warning | Soft warning — warning-bg, warning-text. |
.caat-badge--soft-danger | Soft danger — light red bg, danger-accent text. |
.caat-badge--active | Active status — success-bg, success-text. For member dashboard. |
.caat-badge--pending | Pending status — warning-bg, warning-text. |
.caat-badge--retired | Retired status — blue-100 bg, blue-900 text. |
.caat-badge--count | Counter badge on button — smaller font, pill shape, offset positioning. |
Sample CSS
.caat-badge {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.75rem;
font-weight: 700;
line-height: 1;
padding: 0.35em 0.65em;
border-radius: 0.375rem;
white-space: nowrap;
vertical-align: baseline;
}
.caat-badge--primary {
background-color: var(--caat-blue-900, #003750);
color: #fff;
}
.caat-badge--secondary {
background-color: var(--caat-green-700, #367f32);
color: #fff;
}
.caat-badge--warning {
background-color: var(--caat-warning);
color: var(--caat-ink);
}
.caat-badge--danger {
background-color: var(--caat-danger);
color: #fff;
}
.caat-badge--light {
background-color: var(--caat-grey);
color: var(--caat-ink, #102637);
border: 1px solid var(--caat-grey-200, #dfe6ef);
}
.caat-badge--dark {
background-color: var(--caat-ink, #102637);
color: #fff;
}
.caat-badge--pill {
border-radius: 50rem;
padding: 0.35em 0.75em;
}
.caat-badge--soft-blue {
background: var(--caat-blue-100);
color: var(--caat-blue-900);
}
.caat-badge--active {
background-color: var(--caat-success-bg, #d1e7dd);
color: var(--caat-success-text, #0a3622);
}
.caat-badge--pending {
background-color: var(--caat-warning-bg, #fff3cd);
color: var(--caat-warning-text, #664d03);
}
.caat-badge--retired {
background-color: var(--caat-blue-100, #e7f4fb);
color: var(--caat-blue-900, #003750);
}
8. Accessibility
| Requirement | Implementation |
|---|---|
| Visually hidden context | When a badge conveys meaning (e.g., notification count, status), append a <span class="visually-hidden"> with descriptive text so screen readers announce the full context (e.g., "4 unread messages" instead of just "4"). |
| Colour contrast | All variant text meets WCAG 2.1 AA (4.5:1 minimum). Verified ratios: Primary 12.28:1, Secondary 4.95:1, Info 8.94:1, Warning 10.17:1, Danger 5.57:1, Light 14.94:1, Dark 15.39:1, Soft Blue 12.28:1, Soft Green 11.79:1, Soft Teal 4.58:1, Soft Warning 10.17:1, Soft Danger 6.07:1, Active 14.43:1, Pending 10.17:1, Retired 12.28:1. |
| Colour not sole indicator | Badges should be accompanied by visible text labels or icons — never rely on colour alone to convey status or category. |
| Decorative icons | Icons within badges use aria-hidden="true" since the visible text already provides meaning. |
| Non-interactive | Badges are <span> elements and are not focusable. They do not receive keyboard focus or pointer events independently. |
| Reduced motion | If badge includes any transition/animation (e.g., pulse for new notifications), it respects 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/badge - Component group: CAAT Components – Indicators
- Proxy: Create as a proxy component under
/apps/caat/components/badge. - Policies: Configure allowed badge variants per template via content policies (e.g., public pages may restrict danger badges to admin-only use).
- Sling Model:
com.caat.core.models.BadgeModel— exposestext,variant,pill,hiddenContext,icon. - HTL:
badge.html— usesdata-sly-attributeto set variant class and pill modifier dynamically. - Client library:
caat.components.badge(categories:caat.site). - Style System: Not applicable — variant selection via dedicated dropdown rather than style tab.
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: Badge
description: Small label for categorization, status, or notification counts.
fields:
- name: text
label: Badge Text
type: textfield
required: true
maxLength: 30
helpText: Short label (e.g., "Active", "DBplus", "4"). Max 30 characters.
- name: variant
label: Variant
type: select
required: true
options:
- value: primary
label: Primary (CAAT Blue)
- value: secondary
label: Secondary (CAAT Green)
- value: success
label: Success
- value: info
label: Info
- value: warning
label: Warning
- value: danger
label: Danger
- value: light
label: Light
- value: dark
label: Dark
helpText: Determines badge colour scheme.
- name: pill
label: Pill Shape
type: checkbox
required: false
defaultValue: false
helpText: Applies fully rounded corners. Recommended for status indicators and counters.
- name: hiddenContext
label: Visually Hidden Context
type: textfield
required: false
maxLength: 80
helpText: Screen-reader-only text appended to the badge (e.g., "unread messages"). Required when badge conveys non-decorative meaning.
- name: icon
label: Icon
type: iconpicker
required: false
helpText: Optional Bootstrap Icon displayed before the label text (e.g., bi-check-circle-fill).
13. QA Acceptance Checklist
- All 16 variants (7 solid + outline + 5 soft + 3 status) render with correct background and text colours per design tokens.
- Pill modifier applies
border-radius: 50remand renders as a fully rounded shape. - Badge on button renders as an overlay counter with correct positioning.
- Visually hidden context text is announced by screen readers (tested with NVDA and VoiceOver).
- Colour contrast meets WCAG 2.1 AA (4.5:1) for all variants.
- Badge does not render if text field is empty (validation enforced in dialog).
- Optional icon renders before label text with
aria-hidden="true". - Status badges (Active, Pending, Retired) display correctly on member dashboard tables.
- Badge scales proportionally within different font-size contexts (headings, table cells, buttons).
- Analytics events (
badge-displayed,badge-status-view) fire correctly 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 eight variants documented with colour tokens. Pill and standard shapes provided. Status badge patterns (Active, Pending, Retired) included. |
| Development | AEM proxy component created. HTL template emits semantic HTML per Section 6. CSS uses design tokens exclusively. Visually hidden context wired for screen readers. 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 variant selection and visually-hidden context requirements. Documentation published. Analytics dashboards confirmed receiving events. |