Stats

Molecule
Single value, grouped row, with sparkline, with comparison. Used for dashboards and overview pages.

Playground

Every control sets a real prop of StatsProps. The JSX below updates as you go.
This week
Active users
71,897
+12.3% vs. last 30 days
Props
Surface
pick one
framed
boolean
title
string
JSX · StatsProps
<Stats title="This week" />

Variants

8 examples from src/molecules/stats/stats.md, each rendered live from its own JSX.
Total users
12,847
+12.5%
Error rate
0.12%
+0.03%
Avg. session
4m 32s
last 30 days
Group
<Stats
items={[
{ label: "Total users", value: "12,847", delta: "+12.5%" },
{ label: "Error rate", value: "0.12%", delta: "+0.03%", down: true },
{ label: "Avg. session", value: "4m 32s", delta: "last 30 days", steady: true }
]}
/>
Revenue
$48.2k
Orders
842
Conversion
3.6%
Plain
<Stats
plain
items={[
{ label: "Revenue", value: "$48.2k" },
{ label: "Orders", value: "842" },
{ label: "Conversion", value: "3.6%" }
]}
/>
Active users
12,348
Sessions
489
Per-tile icon, control and accent
<Stats
items={[
{ label: "Active users", value: "12,348", icon: <Icon users muted size={16} />, chart1: true },
{ label: "Sessions", value: "489", actions: <Button ghost small>7d</Button>, chart2: true }
]}
/>
Requests
24.5k
+8.2%
Sparkline
<Stats
items={[
{ label: "Requests", value: "24.5k", delta: "+8.2%", spark: [4, 8, 6, 12, 10, 16, 14, 18] }
]}
/>
Verified identities
81.3%
1,502 of 1,847 verified
Composition strip
A metric that has no trend to plot usually still decomposes. share draws that composition over a muted rail, in the same slot and at the same height as the sparkline, so it fills the tile with something true rather than with padding.
<Stats
items={[
{ label: "Verified identities", value: "81.3%", delta: "1,502 of 1,847 verified", steady: true, share: [{ label: "Verified", value: 1502 }, { label: "Unverified", value: 345 }] }
]}
/>
Requests
24.5k
+8.2%
Errors
0
None in the last hour
Framed strips
Without a frame each strip draws only its marks, so a quiet series shows a near-empty band beside a full bar and the row's densities range from blank to solid. framed gives every strip the same track whatever its data: a flat series then reads as a chart sitting at zero, and the fill is the only thing that varies.
<Stats
framed
items={[
{ label: "Requests", value: "24.5k", delta: "+8.2%", spark: [4, 8, 6, 12, 10, 16, 14, 18] },
{ label: "Errors", value: "0", delta: "None in the last hour", steady: true, spark: [0, 0, 0, 0, 0, 0, 0, 0] }
]}
/>
Requests
24.5k
+8.2%
Verified identities
81.3%
1,502 of 1,847 verified
Mixed strips in one row
<Stats
framed
items={[
{ label: "Requests", value: "24.5k", delta: "+8.2%", spark: [4, 8, 6, 12, 10, 16, 14, 18] },
{ label: "Verified identities", value: "81.3%", delta: "1,502 of 1,847 verified", steady: true, share: [{ label: "Verified", value: 1502 }, { label: "Unverified", value: 345 }] }
]}
/>
Tappable
<Stats
onPressItem={() => {}}
items={[
{ label: "Active users", value: "71,897" },
{ label: "Revenue", value: "$48.2k" }
]}
/>

Anatomy

This week
Active users
71,897
+12.3% vs. last 30 days
1
Group
2
Stat
3
Label
4
Value
5
Delta
Dimmed parts appear only in some states or variants.

Props

9 props on StatsProps, grouped as they are declared in source. Required props are marked *.
Prop
Type
Default
Description
Props
1 prop
items *
StatItem[]
–
The metrics to render, in order.
Surface
pick one
8 props
plain
boolean
false
Borderless metric stacks on a shared surface, for nesting inside a card.
compact
boolean
false
Dense value-first tile for a navigation rail: a 12px inset and a 20px headline.
large
boolean
false
Value-first dashboard tile with a 36px headline.
title
string
–
Optional heading shown above the metrics (mainly for the plain surface).
framed
boolean
false
Draw every metric's strip on a muted track, in one bounded band. For a ROW of metrics, where the strips are read against each other. Without it each strip draws only its marks, so a metric with a quiet series shows a near-empty band beside one with a full bar and the row's densities range from blank to solid with nothing tying them together; the eye lands on the fullest tile rather than scanning the row. The track gives every strip the same frame whatever its data, so a flat series reads as a chart sitting at zero and the fill is the only thing that varies.
onPressItem
(index: number) => void
–
Make each metric a tappable target (drill into the underlying detail). When set, every metric renders as a Pressable with a button role and a pressed affordance, so a tappable stat needs no hand-rolled Pressable.
testID
string
–
E2E hook forwarded to the root element.
style
LayoutStyle
–
Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds.

Accessibility and keyboard

Keyboard
Not focusable. It has no interaction of its own and takes the semantics of what it wraps.
Semantics
Roles
button

Platform skins

The playground's props on each platform: same tree, native shapes, type and touch sizes.
Web
control 10 · field 10 · card 16 · Instrument Sans
iOS
capsule controls · field 8 · card 12 · SF Pro · 44 pt
Android
Material 3 stadium · field 4 · card 12 · Roboto · 48 dp

Usage

<Stats
items={[
{ label: "Active users", value: "71,897", delta: "+12.3% vs. last 30 days" }
]}
/>
Under the value each tile can draw one strip: its trend (spark) or its composition (share). Both reserve the same height, so a row that mixes them keeps one card height and no tile is left half empty. framed puts every strip on a muted track, which is what makes a ROW of them scan evenly.
Each metric is a tile: the card fill on a hairline at the card corner, an 18px inset, a 12px label, a 28px figure and a 12px mono delta. plain sets the metrics edge to edge inside one bordered surface, a hairline between each. compact renders value-first rail tiles with a 12px inset and 20px figures; large renders 36px dashboard headlines; compact wins if both are set. Each item may include a muted description.

Tokens

Read from the playground render. Values follow the scheme and the ion hue.
--bad
--f-dp
--fd
--fm
--ft
--ln
--ok
--sf
--sh-sm
--tx3

Related components