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

Primary Secondary Info Warning Danger Light Dark

Pill Badges

Rendered

DBplus DBprime Information Review Required Overdue

Soft Pill Badges (category labels on cards)

Rendered

Pension Insights Plan Updates New Feature Action Needed Deprecated General

Badge on Button

Rendered

Status Badges (Member Dashboard)

Rendered

Active Pending Retired

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 namecaat/components/badge
PurposeSmall 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.
StatusActive
VariantsPrimary, Secondary, Info, Warning, Danger, Light, Dark, Outline, Soft Blue, Soft Green, Soft Teal, Soft Warning, Soft Danger, Active, Pending, Retired
OptionsPill shape toggle, optional leading icon
AEM resource typecaat/components/badge
AEM categoryCAAT Components – Indicators

2. Design Tokens

Token / ValueRoleResolved Value
--caat-blue-900Primary background#003750
--caat-green-700Secondary background#367f32
--caat-infoInfo background#0dcaf0
--caat-warningWarning background#efaa39
--caat-dangerDanger background#b83232
--caat-greyLight background#eff2f7
--caat-inkDark background / dark text colour#102637
--caat-grey-200Outline border / Light border#dfe6ef
--caat-blue-100Soft blue background / Retired background#e7f4fb
--caat-green-100Soft green background#e8f5e6
--caat-green-900Soft green text#204b1f
--caat-warning-bgSoft warning / Pending background#fff3cd
--caat-warning-textSoft warning / Pending text#664d03
--caat-danger-bgSoft danger background#fde8e8
--caat-danger-accentSoft danger text#c0392b
--caat-success-bgActive status background#d1e7dd
--caat-success-textActive status text#0a3622
(hardcoded)Soft teal background#e4f7f8
(hardcoded)Soft teal text#0a7a86

3. Authoring Fields

FieldTypeRequiredNotes
TextText fieldYesThe visible badge label. Max 30 characters. Examples: "Active", "DBplus", "4".
VariantDropdown (primary | secondary | success | info | warning | danger | light | dark)YesDetermines colour scheme. Primary maps to CAAT blue-900; secondary to CAAT green.
PillToggle (boolean)NoDefault: off. When enabled, applies fully rounded corners (caat-badge--pill).
Visually Hidden ContextText fieldNoScreen-reader-only text appended after the badge label (e.g., "unread messages"). Required when badge conveys meaning beyond decoration.
IconIcon pickerNoOptional 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

GuidelineDetail
ToneShort, factual labels. One or two words maximum for text badges; numerals only for counters.
Use Primary forPlan identifiers — "DBplus", "DBprime". Default categorization labels.
Use Secondary forSupplementary categories — employer type, contribution tier.
Use Success forPositive statuses — "Active", "Enrolled", "Confirmed".
Use Warning forPending states — "Pending", "Review Required", "Expiring Soon".
Use Danger forUrgent indicators — notification counts, "Overdue", "Action Required".
Use Info forNeutral informational labels — "New", "Updated", "Beta".
Use Soft variants forCategory pills on blog/resource cards — Soft Blue for pension news, Soft Green for employer content, Soft Teal for investment topics.
Use Status badges forMember dashboard — Active (enrolled), Pending (awaiting action), Retired (former member). Always shown as pills.
Use Outline forSubtle, non-coloured category labels on cards where a softer visual treatment is needed.
Pill shapePreferred for status indicators, category labels on cards, and notification counters. Use standard (rectangular) for inline categorical labels.
Don'tUse 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

SelectorPurpose
.caat-badgeBase badge — inline-flex, font-size, padding, border-radius, font-weight 700, vertical alignment.
.caat-badge--primaryPrimary colour scheme (CAAT blue-900 background, white text).
.caat-badge--secondarySecondary colour scheme (CAAT green-700 background, white text).
.caat-badge--warningWarning colour scheme (amber background, dark text).
.caat-badge--dangerDanger colour scheme (red background, white text).
.caat-badge--infoInfo colour scheme (cyan background, dark text).
.caat-badge--lightLight colour scheme (light grey background, dark text).
.caat-badge--darkDark colour scheme (dark background, white text).
.caat-badge--pillPill modifier — applies border-radius: 50rem for fully rounded shape.
.caat-badge--outlineLight outline style — transparent bg, grey-200 border, ink text.
.caat-badge--soft-blueSoft blue — blue-100 bg, blue-900 text. For category pills on cards.
.caat-badge--soft-greenSoft green — green-100 bg, green-900 text.
.caat-badge--soft-tealSoft teal — light teal bg, teal-dark text.
.caat-badge--soft-warningSoft warning — warning-bg, warning-text.
.caat-badge--soft-dangerSoft danger — light red bg, danger-accent text.
.caat-badge--activeActive status — success-bg, success-text. For member dashboard.
.caat-badge--pendingPending status — warning-bg, warning-text.
.caat-badge--retiredRetired status — blue-100 bg, blue-900 text.
.caat-badge--countCounter 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

RequirementImplementation
Visually hidden contextWhen 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 contrastAll 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 indicatorBadges should be accompanied by visible text labels or icons — never rely on colour alone to convey status or category.
Decorative iconsIcons within badges use aria-hidden="true" since the visible text already provides meaning.
Non-interactiveBadges are <span> elements and are not focusable. They do not receive keyboard focus or pointer events independently.
Reduced motionIf 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 — exposes text, variant, pill, hiddenContext, icon.
  • HTL: badge.html — uses data-sly-attribute to 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: 50rem and 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

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