Stat

A label, a value and an optional change

The first span is the label and strong is the value. An optional span[data-trend] shows how it changed.

New orders 128 12.5%

One stat in a card

Net revenue $1,377.43 4.2%

A link to the records and an info button on the label

The whole stat can be an a, and the value turns the accent color. For an explanation, a button in the label opens a .popover (place the popover outside the link).

Total sales $4,148.64 40.1%

Total sales from all orders before returns.

Trend colors: data-trend up is green, down is red, empty is gray

Rising 128 12.5%
Falling 96 25.0%
Unchanged 40 0.0%
No comparison 7

data-reverse: when a rise is bad news

Add data-reverse to a stat to swap the colors: up is red, down is green.

Returns 14 40.0%
Time to fulfill 0.9 days 18.0%

Loading: aria-busy="true" shows a spinner in place of the value

Put a .loader in the stat and toggle aria-busy while fetching data. The value and the change are hidden.

New orders 128 12.5%
Items ordered 342 8.1%

A control beside the group stays outside it

The date range picker sits in a data-direction="row" card next to the .stat-group, not inside it, because the group clips overflow.

New orders 128 12.5%
Items ordered 342 8.1%
Returns 6 25.0%
Fulfilled 117 9.3%
Time to fulfill 1.4 days
Delivered 102 3.0%

Linked small stats beside a page title

data-size="sm" makes a small centered box. One here is data-variant="danger" and another is still loading.

Stats that pick what a chart shows

Each stat is a button, and the selected one has aria-pressed="true". data-even on the group makes every cell the same width.

Legacy multi-cell box

dl.stat still works: each div has a dt label and a dd value. For new work, use .card > .stat-group instead.

Revenue
$3,668
+12.4% from last month
Refunds
18
+2 items

Attributes

Attribute / element Values Description
.stat div, a, button A single figure; a when the whole cell is a link (accent-colored value), button when it picks what to show
> span:first-child 12px gray label, cut off with … when it does not fit; a trailing icon button can open an explanation
> strong 24px value with tabular numbers
> span[data-trend] up, down; empty = gray The change, on the right of the value's row. up = ok color, down = danger color; add a leading icon
> .loader Spinner shown in place of the value when aria-busy="true" (hidden otherwise)
aria-busy true; omit to show the value (default) Hides the value and the change, shows the .loader
aria-pressed true, false On button.stat: the selected one gets a darker gray fill
data-reverse (boolean) Swaps the colors: up is danger, down is ok. For figures where a rise is bad
data-variant danger; omit for normal (default) Red label and value, for counts that signal a problem
data-size sm; omit for normal (default) Small bordered box, centered, for use beside a page title
.stat-group div A row of stats separated by lines. Wraps on narrow screens. Runs edge to edge inside a .card
.stat-group[data-even] (boolean) Every cell gets the same width, but never narrower than its text
dl.stat div > dt + dd + dd Legacy: several cells in one box; dd[data-variant] = ok, danger