Stats Card
A metric, its label and icon, and its change against the last period.
Spending went up, and that’s bad news: it’s red. The color follows whether the change is good, not only its direction.
The recent values as a line under the value. The line takes the color of the change: green, red, or the primary color when the trend is flat.
How far the value is from a goal. Past the goal, the bar stays full and turns green.
Icon, label, value and change on one line. For a stack of metrics, or a dashboard that shows many at once.
A ring for the share of a goal, the percentage in its middle. Past the goal, the ring turns green.
The variants are separate components with their own code: install the one you need.
Installation
npx axiom add stats-cardpnpm dlx axiom add stats-cardyarn dlx axiom add stats-cardbun x axiom add stats-cardAlso copies: card, badge, icon, title, text and their dependencies. The file lands in components/compositions/stats-card.tsx. It brings no tokens of its own.
npx axiom add stats-card-sparklinepnpm dlx axiom add stats-card-sparklineyarn dlx axiom add stats-card-sparklinebun x axiom add stats-card-sparklineAlso copies: card, badge, icon, title, text and their dependencies. The file lands in components/compositions/stats-card-sparkline.tsx. It brings no tokens of its own.
Needs react-native-svg, a native module: rebuild your development build after installing it.
npx axiom add stats-card-progresspnpm dlx axiom add stats-card-progressyarn dlx axiom add stats-card-progressbun x axiom add stats-card-progressAlso copies: card, icon, title, text and their dependencies. The file lands in components/compositions/stats-card-progress.tsx. It brings no tokens of its own.
npx axiom add stats-card-inlinepnpm dlx axiom add stats-card-inlineyarn dlx axiom add stats-card-inlinebun x axiom add stats-card-inlineAlso copies: card, badge, icon, title, text and their dependencies. The file lands in components/compositions/stats-card-inline.tsx. It brings no tokens of its own.
npx axiom add stats-card-ringpnpm dlx axiom add stats-card-ringyarn dlx axiom add stats-card-ringbun x axiom add stats-card-ringAlso copies: card, title, text and their dependencies. The file lands in components/compositions/stats-card-ring.tsx. It brings no tokens of its own.
Needs react-native-svg, a native module: rebuild your development build after installing it.
Usage
import { StatsCard } from "@/components/compositions/stats-card";
<View style={{ flexDirection: "row", gap: 12 }}>
<StatsCard
label="Revenue"
value="$12,480"
icon="wallet"
change="+12.4%"
trend="up"
caption="vs last week"
style={{ flex: 1 }}
/>
<StatsCard
label="Spending"
value="$3,210"
icon="cart"
change="+8%"
trend="up"
positive={false}
style={{ flex: 1 }}
/>
</View>;import { StatsCardSparkline } from "@/components/compositions/stats-card-sparkline";
<StatsCardSparkline
label="Revenue"
value="$12,480"
icon="wallet"
data={last7Days.map((day) => day.revenue)}
change="+12.4%"
trend="up"
caption="Last 7 days"
style={{ flex: 1 }}
/>;data is scaled between its own minimum and maximum: the line shows the shape of the series, not its distance from zero. Two points at least; a dozen reads best at this size.
import { StatsCardProgress } from "@/components/compositions/stats-card-progress";
<StatsCardProgress
label="Steps"
value={formatNumber(steps)}
goal={`/ ${formatNumber(goal)}`}
progress={steps / goal}
icon="flame"
caption={`${formatNumber(goal - steps)} to go`}
/>;import { StatsCardInline } from "@/components/compositions/stats-card-inline";
<View style={{ gap: 8 }}>
<StatsCardInline label="Revenue" value="$12,480" icon="wallet" change="+12.4%" trend="up" onPress={openRevenue} />
<StatsCardInline label="Refunds" value="$212" icon="cart" change="+4%" trend="up" positive={false} />
</View>;import { StatsCardRing } from "@/components/compositions/stats-card-ring";
<StatsCardRing
label="Move"
value="420 kcal"
progress={420 / 600}
caption="of 600 kcal"
/>;Pass ringLabel to replace the percentage in the ring, with something short: "3/5".
Values come formatted: the card never rounds or localizes a number.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | What is measured, muted, above the value. |
value | string | — | Already formatted, in large type. Shrinks to fit one line. |
icon | IconName | — | Before the label. |
change | string | — | Change against the previous period, in a Badge: "+12.4%". |
trend | 'up' | 'down' | 'flat' | 'flat' | Direction of the change. flat keeps the badge neutral. |
positive | boolean | trend !== 'down' | Whether the change is good news: green if so, red if not. Pass false for spending or latency going up. |
caption | string | — | After the change: "vs last week". |
variant | 'elevated' | 'outlined' | 'filled' | 'filled' | The Card variant. |
onPress | () => void | — | Makes the card pressable, to open the detail. |
style | StyleProp<ViewStyle> | — | Extra styles, usually flex: 1 in a row of cards. |
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | What is measured, muted, above the value. |
value | string | — | Already formatted, in large type. |
data | number[] | — | The recent values, oldest first. Drawn as a 40pt line across the card. |
icon | IconName | — | Before the label. |
change | string | — | In a Badge next to the value. |
trend | 'up' | 'down' | 'flat' | 'flat' | Colors the badge and the line. |
positive | boolean | trend !== 'down' | Whether the change is good news. |
caption | string | — | Under the line: "Last 7 days". |
variant | 'elevated' | 'outlined' | 'filled' | 'filled' | The Card variant. |
onPress | () => void | — | Makes the card pressable. |
style | StyleProp<ViewStyle> | — | Extra styles, usually flex: 1. |
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | What is measured. |
value | string | — | Already formatted. |
goal | string | — | The target, muted after the value: "/ 10,000". |
progress | number | — | Share of the goal, from 0 to 1. Above 1, the bar stays full and turns green. |
icon | IconName | — | Before the label. |
caption | string | — | Under the bar, on the right: "1,796 to go". The percentage is on the left. |
variant | 'elevated' | 'outlined' | 'filled' | 'filled' | The Card variant. |
onPress | () => void | — | Makes the card pressable. |
style | StyleProp<ViewStyle> | — | Extra styles for the card. |
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | What is measured, muted, after the icon. |
value | string | — | Already formatted, on the right. |
icon | IconName | — | In a 32pt tile at the start of the row. |
change | string | — | In a Badge after the value. |
trend | 'up' | 'down' | 'flat' | 'flat' | Colors the badge. |
positive | boolean | trend !== 'down' | Whether the change is good news. |
variant | 'elevated' | 'outlined' | 'filled' | 'filled' | The Card variant. |
onPress | () => void | — | Makes the row pressable. |
style | StyleProp<ViewStyle> | — | Extra styles for the card. |
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | What is measured. |
value | string | — | Already formatted, next to the ring. |
progress | number | — | Share of the goal, from 0 to 1. Above 1, the ring stays full and turns green. |
caption | string | — | Under the value: "of 600 kcal". |
ringLabel | string | the percentage | Inside the 64pt ring. |
variant | 'elevated' | 'outlined' | 'filled' | 'filled' | The Card variant. |
onPress | () => void | — | Makes the card pressable. |
style | StyleProp<ViewStyle> | — | Extra styles for the card. |
Accessibility
The card reads as one sentence: “Revenue: $12,480, +12.4%, vs last week”. The sparkline is hidden from screen readers: the value and the change already say what it shows.
Progress and Ring are progress bars: they announce their percentage along with the label, “Steps: 8,204, / 10,000, 82%, 1,796 to go”.
Built with
- Card: the filled surface.
- Title: the value.
- Badge: the change, in success, error or neutral.
- Icon and Text: the label and the caption.
react-native-svg: the line of Sparkline and the arc of Ring.
Used in
No block uses Stats Card yet.
Related
- Profile Card: stats inside a profile.
- Compositions