Stat Card
import { StatCard } from '@absoluteui/components/stat-card';import '@absoluteui/components/stat-card/style.css';Using Angular? See Stat Card for Angular.
What it does
Section titled “What it does”A KPI / metric card. StatCard renders a headline value with its label, an optional change against a previous value, a comparison caption, an optional trend Sparkline, and supporting text. The change shows an arrow and a signed amount and is spelled out for assistive technology (“increase of 20%, favorable”; the direction word carries the sign, since 0.9.0), so its meaning never depends on color. sentiment decides whether an increase is favorable. The card is a role="group" named by its label; with href the whole card is one link.
When to use
Section titled “When to use”- Headline metrics on dashboards: revenue, active users, error rate, with the change since the previous period.
- KPI tiles that link to a detail page (href).
When not to use
Section titled “When not to use”- Comparing many values or showing a series in detail: use a chart or Data Table.
- Progress toward a goal: use Progress Bar (or a gauge chart).
- Cards with several interactive controls: use Card.
Examples
Section titled “Examples”Revenue with the change against last month and a trend
Section titled “Revenue with the change against last month and a trend”import { StatCard } from '@absoluteui/components/stat-card';
const host = document.createElement('div');document.body.append(host);const card = StatCard.create(host, { label: 'Revenue', value: 48200, previous: 40100, valueFormat: { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }, comparisonLabel: 'vs last month', trend: [31000, 35500, 38200, 40100, 48200],});host.dataset.delta = String(card.delta);Error rate where a decrease is favorable, linking to details
Section titled “Error rate where a decrease is favorable, linking to details”import { StatCard } from '@absoluteui/components/stat-card';
const host = document.createElement('div');document.body.append(host);StatCard.create(host, { label: 'Error rate', value: 0.012, valueFormat: { style: 'percent', maximumFractionDigits: 1 }, delta: -0.003, deltaFormat: 'absolute', sentiment: 'lower-is-better', comparisonLabel: 'vs yesterday', href: '/reports/errors',});Loading state, then the value
Section titled “Loading state, then the value”import { StatCard } from '@absoluteui/components/stat-card';
const host = document.createElement('div');document.body.append(host);const card = StatCard.create(host, { label: 'Active users', value: null, busy: true });export function showActiveUsers(count: number, previous: number): void { card.update({ busy: false, value: count, previous });}Absolute changes for every card
Section titled “Absolute changes for every card”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { statCard: { deltaFormat: 'absolute' } } });import { StatCard } from '@absoluteui/components/stat-card';import '@absoluteui/components/stat-card/style.css';import '@absoluteui/components/sparkline/style.css';
const host = document.querySelector<HTMLElement>('#errors');if (host) { StatCard.create(host, { label: 'Error rate', value: 0.012, valueFormat: { style: 'percent', maximumFractionDigits: 1 }, previous: 0.015, sentiment: 'lower-is-better', comparisonLabel: 'vs yesterday', trend: [0.02, 0.018, 0.015, 0.012], href: '/reports/errors', });}More usage
Section titled “More usage”import { StatCard } from '@absoluteui/components/stat-card';
const host = document.querySelector<HTMLElement>('#revenue');if (host) StatCard.create(host, { label: 'Revenue', value: 48200, previous: 40100, valueFormat: { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }, comparisonLabel: 'vs last month' });Anatomy
Section titled “Anatomy”<div class="aui-stat-card"> (consumer host; children replaced) <div class="aui-stat-card__body" role="group" aria-labelledby> (<a class="aui-stat-card__body aui-stat-card__link" href> with href) <span class="aui-stat-card__top">[icon.aui-stat-card__icon]<span class="aui-stat-card__label" id>Revenue</span></span> <span class="aui-stat-card__value">$48,200</span> <span class="aui-stat-card__change"> (when there is a change) <span class="aui-stat-card__delta aui-stat-card__delta--good|--bad|--neutral"> [arrow.aui-stat-card__arrow]<span aria-hidden="true">+20.2%</span><span class="aui-stat-card__sr">increase of 20.2%, favorable</span> </span> <span class="aui-stat-card__comparison"> vs last month</span> </span> <span class="aui-stat-card__trend">(Sparkline)</span> (trend) <span class="aui-stat-card__description"> (description)API reference
Section titled “API reference”Factory
Section titled “Factory”StatCard.create(host: HTMLElement, options: StatCardOptions): StatCardGlobal configuration key: statCard (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Metric name; names the card (group) and, by default, the trend sparkline. Non-empty. Required. | |
value |
number | string | null |
A number (formatted with valueFormat or formatValue), preformatted text, or null (‘No value’). Required. | |
previous |
number | null |
Previous value; the change is computed from it when value is a number (percent: (value - previous) / |previous|, not shown for 0; absolute: value - previous). Finite. | |
delta |
number | null |
Explicit change (a ratio for ‘percent’, units for ‘absolute’); wins over previous. Finite. | |
comparisonLabel |
string |
Caption after the change, for example ‘vs last month’ (shown only with a change). | |
description |
string |
Supporting text at the bottom. | |
trend |
readonly (number | null)[] |
Trend values rendered as a Sparkline (null is a gap); an empty array shows none. | |
trendLabel |
string |
Sparkline accessible label. Default: the card label. | |
trendColor |
SparklineColor |
1 |
Chart palette slot of the sparkline (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; SparklineColor from @absoluteui/components/sparkline). |
valueFormat |
Intl.NumberFormatOptions |
Number format of the value (and of an absolute change). | |
formatValue |
(value: number) => string |
Custom value formatter; wins over valueFormat (also used for an absolute change). | |
icon |
IconRef |
Decorative icon before the label. | |
href |
string |
Make the whole card a link (http(s) or relative URLs only; others throw). The URL can change with update(), but adding or removing href throws. Set at creation only. | |
busy |
boolean |
false |
Show ‘Loading’ instead of the value (no change) and set aria-busy. |
sentiment |
'higher-is-better' | 'lower-is-better' | 'neutral' |
"higher-is-better" |
Whether an increase is favorable, unfavorable, or neither; decides the color and the spoken ‘favorable’/‘unfavorable’. Globally configurable. |
deltaFormat |
'percent' | 'absolute' |
"percent" |
Relative change (percent, max 1 fraction digit) or the difference in value units. Globally configurable. |
locale |
string |
"en-US" |
Number formatting and message locale. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
Passed to the trend sparkline. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host; its children are owned by the component. |
delta |
number | null |
The change as displayed (ratio or units), or null. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<StatCardOptions>): void |
Merge, validate, and re-render. Adding or removing href throws. |
destroy(): void |
Destroy the sparkline, remove the rendering, the host class, and the configuration subscription. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-stat-card |
Host. |
aui-stat-card__body |
Card root: a div (role=group) or, with href, an a element (also aui-stat-card__link). |
aui-stat-card__top | __icon | __label |
Label row, icon, label. |
aui-stat-card__value |
Headline value (tabular numerals). |
aui-stat-card__change | __delta | __arrow | __comparison |
Change row, change amount, arrow icon, comparison caption. |
aui-stat-card__delta--good | --bad | --neutral |
Favorable, unfavorable, or neutral/no change. |
aui-stat-card__sr |
Visually hidden spelled-out change for assistive technology. |
aui-stat-card__trend |
Sparkline host. |
aui-stat-card__description |
Supporting text. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
icon (option) |
none |
increase arrow |
arrow-up |
decrease arrow |
arrow-down |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-hover | --aui-color-success-fg | --aui-color-surface | --aui-color-text | --aui-color-text-muted | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-sm | --aui-font-size-xl | --aui-font-weight-medium | --aui-font-weight-semibold | --aui-line-height-tight | --aui-radius-lg | --aui-space-1 | --aui-space-2 | --aui-space-inset
TypeScript definitions
Section titled “TypeScript definitions”type StatCardSentiment = 'higher-is-better' | 'lower-is-better' | 'neutral';type StatCardDeltaFormat = 'percent' | 'absolute';interface StatCardConfig { sentiment: StatCardSentiment; deltaFormat: StatCardDeltaFormat }Accessibility
Section titled “Accessibility”Pattern: Static content grouped with role=group and named by its visible label; with href, a single native link wrapping the whole card. The change is spelled out in visually hidden text; the visible signed amount is aria-hidden so it is not read twice.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Card with href | The card is one tab stop (the link). |
| Enter | Card link focused | Follows the link (native). |
| Tab / Shift+Tab | Card without href | Not focusable; focus passes by. |
| Element | Role |
|---|---|
| card root (no href) | group, named by the label (aria-labelledby) |
| card root (href) | link (native <a href>), named by its content |
| icon, arrow | none (decorative icons) |
| trend | Sparkline (see sparkline accessibility metadata) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-labelledby |
card root (no href) | id of the label element |
aria-busy |
card root | “true” while busy |
aria-hidden |
visible signed change amount | “true”; the visually hidden text reads ‘{increase|decrease|no change} of {amount}[, favorable|unfavorable]’ |
A linked card shows a focus-ring-width outline in color-focus-ring with focus-ring-offset. A plain card is not focusable.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.1.1 Non-text Content | A | |
| 1.3.1 Info and Relationships | A | |
| 1.4.1 Use of Color | A | |
| 1.4.3 Contrast (Minimum) | AA | |
| 2.4.4 Link Purpose (In Context) | A | |
| 2.4.7 Focus Visible | AA | |
| 4.1.2 Name, Role, Value | A |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Favorable/unfavorable is conveyed by text (‘increase of 20%, favorable’; the sign is spoken as the direction word) and by the arrow direction, not by color alone (WCAG 1.4.1).
- Sentiment ‘neutral’ and a zero change omit the favorable/unfavorable wording.
- While busy the value reads ‘Loading’ and the change is not shown.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
- A linked card’s accessible name is its whole text content (label, value, spelled-out change, caption, and description), which can be long.
Behavior
Section titled “Behavior”States
Section titled “States”default, busy, no value, increase/decrease x favorable/unfavorable, no change or neutral, link hover, link focus-visible.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| busy | update({ busy: false, value }) |
value shown; change computed |
| any | update({ value, previous }) |
re-rendered; change recomputed |
| any | sentiment changes (option or global) |
favorable/unfavorable wording and color flip |
Accessibility notes
Section titled “Accessibility notes”- Meaning never depends on color (WCAG 1.4.1): direction and favorability are text; the arrow shows direction.
neutralsentiment and zero changes omit “favorable”/“unfavorable”.- A linked card’s name is its whole text, which can be long; keep descriptions short.
- Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”Fills its container (block-size: 100%, so it fills a Dashboard Grid cell). Text wraps; numbers use tabular figures. The sparkline spans the card width at 2rem height.
Right-to-left
Section titled “Right-to-left”Logical properties; the sparkline receives the resolved direction. Intl formats numbers and signs for the locale.
Theming
Section titled “Theming”Favorable changes use color-success-fg, unfavorable color-error-fg, neutral color-text. Forced colors: CanvasText for the border and all change colors.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { statCard: { deltaFormat: 'absolute', sentiment: 'neutral' } } });Global options: sentiment, deltaFormat, plus inherited locale and direction. Changes apply to existing cards immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic, except that href cannot be added or removed after create.
icon (any IconRef, decorative). The change arrow uses arrow-up / arrow-down.
Security
Section titled “Security”All text uses textContent. href must pass the URL policy (http, https, or scheme-less relative); javascript:, data:, and other schemes throw STAT_CARD_OPTIONS. CSP-safe.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. Formatting happens locally.
Performance
Section titled “Performance”Each render rebuilds a few spans and updates the sparkline in place. One configuration subscription per card. Budget: StatCard.create < 2 ms in headless Chromium (e2e performance test).
Supported data scale
Section titled “Supported data scale”Tens of cards per dashboard. Trend arrays follow the Sparkline limits.
Edge cases
Section titled “Edge cases”previous: 0withpercent: no change is shown (division by zero); passdelta.- A string
valuenever computes a change; passdelta. - With
formatValueandabsolute, positive changes get a “+” prefix; negative ones rely onformatValuefor the minus sign. comparisonLabelshows only when there is a change.- An empty
trendremoves the sparkline.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
STAT_CARD_OPTIONS |
configuration | Empty label; invalid value, non-finite previous/delta, non-string texts, invalid trend, unsafe href, non-boolean busy, invalid valueFormat or formatValue; adding/removing href in update(). |
Known limitations
Section titled “Known limitations”- The trend needs the Sparkline stylesheet (
@absoluteui/components/sparkline/style.css) too. hrefpresence is fixed at create time.- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML in texts.
- Controls inside the card.
- Several values per card.