Stat cards
Revenue
vs last month
Usage
Import the component and the stylesheet once. See Getting started to install the package.
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';<StatCard
title="Revenue"
data={dailyKpis}
value="revenue"
x="date"
delta={0.124}
caption="vs last month"
/>Omit title to leave out the visible title. Set header={false} to remove the whole header, and use aria-label to name a chart inside your own card. surface="ghost" controls only the visual frame. See Card composition.
Data
value names the numeric field to chart, and TypeScript rejects fields that don’t exist or aren’t numbers. The big number is that field summed over the rows; use aggregate for levels (last) or rates (mean). x is optional and only names points on hover. null is a gap in the chart and is left out of the summary, never counted as zero.
// One row per observation. Several tiles can share the same rows.
const dailyKpis = [
{ date: new Date('2026-09-01'), revenue: 3120, activeUsers: 1840 },
{ date: new Date('2026-09-02'), revenue: 3380, activeUsers: 1910 },
];
<StatCard title="Revenue" data={dailyKpis} value="revenue" x="date" />
<StatCard title="Active users" data={dailyKpis} value="activeUsers" aggregate="last" />
// Already have the number? Pass it directly.
<StatCard title="Seats" headline={128} chart="none" />Props
Every prop StatCard accepts, in the order you are likely to reach for them.
| Prop | Type | Description |
|---|---|---|
title | string | Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set. |
header | boolean | Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection. |
aria-label | string | Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name. |
data | Row[] | One row per observation. Optional when you pass `headline`. |
value | key of Row | Numeric field to summarize and chart. |
x | key of Row | Text, number, or Date field that names each point on hover. |
aggregate | 'sum' | 'mean' | 'last' | 'max' | How the big number summarizes the rows. Defaults to sum. |
headline | number | Set the resting number yourself. |
delta | number | Fractional change: 0.124 shows +12.4%. |
deltaTone | 'default' | 'inverse' | 'neutral' | Use inverse when a decrease is good, such as churn. |
caption | string | Quiet text beside the change chip. |
chart | 'area' | 'line' | 'bars' | 'meter' | 'ring' | 'none' | The small chart. Area by default; meter and ring fill toward `target`, the ring beside the value. |
barStyle | 'solid' | 'segmented' | 'needle' | 'gradient' | 'outline' | 'isometric' | Bar treatment when `chart` is bars. |
target | number | Goal for the meter or ring, in the value’s unit. |
sync | string | Hover together with every card that shares this name, matched by x. Requires `x`. |
height | number | Chart height, and the ring’s size. 56 by default, 10 for a meter. |
color | string | Any CSS color for the chart. |
aside | ReactNode | Header content on the right, e.g. an icon. |
depth | boolean | Lines and the ring become lit tubes, the meter a solid bar, and bars default to `isometric`. |
valueFormat | Intl.NumberFormatOptions | Formats the headline, tiles, and axis, e.g. currency. |
surface | 'elevated' | 'outline' | 'ghost' | Card treatment. Ghost removes the visual frame only; header and legend are independent controls. |
palette | 'iris' | 'cobalt' | 'emerald' | Series colors. Iris by default; explicit series colors still win. |
numberStyle | 'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble' | How the headline animates when its value changes. Count (default) counts to the new value. |
loading | boolean | Shows a neutral loading skeleton, not data. |
loadingStyle | 'shimmer' | 'draw' | 'breathe' | Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion. |
empty | 'dots' | 'shape' | ReactElement | null | What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `<ChartEmpty>` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero. |
motion | 'auto' | 'none' | None turns off decorative motion; reduced motion does this automatically. |
locale | string | Locale used for number formatting. Defaults to en-US. |
formatValue | (value: number) => string | Custom value text, taking precedence over valueFormat. |
formatX | (value: string | number | Date) => string | Custom x label text. |
xType | 'category' | 'number' | 'time' | Override inferred x type. Use time for numeric Unix timestamps in milliseconds. |
badge | ReactNode | Content in the tab above the card. A comparison badge can replace this while a comparison is active. |
className | string | Additional class on the card frame. |
style | CSSProperties | ChartStyle | Inline styles and scoped --lilt-* chart variables. |