KPI statFree
One number with its change in words, an optional target meter and sparkline. Plain SVG: no chart engine.
npx shadcn@latest add https://beautifulcharts.dev/r/kpi-stat.jsonCode
"use client";
import { KpiStat } from "@/components/beautiful-charts/themes/instrument/kpi-stat";
// A change from a zero base is shown as an amount, never as an infinite percentage.
export function ActiveTeams() {
return (
<KpiStat
title="Active teams"
value={74}
previous={38}
previousLabel="last week"
target={80}
trend={[38, 42, 40, 47, 51, null, 55, 61, 63, 64, 69, 74]}
unit="teams with a weekly session"
/>
);
}
Props
value*
number | null
The number. null or undefined shows the empty state.
previous
number | null
The comparison value, e.g. last period.
previousLabel
string
What the comparison is, e.g. "last month".
target
number | null
A goal. Adds a meter showing progress toward it.
trend
(number | null)[]
Recent values, oldest first, for the sparkline. Missing values break the line.
polarity
"up" | "down"
"up" when a rise is good (default), "down" for costs, churn, latency.
valueFormatter
(value: number) => string
Formats the number, change and target.
motion
MotionPreference
"full" (default), "subtle" or "off". Reduced-motion settings always win.
eyebrow
ReactNode
Small label above the title.
footer
ReactNode
A line or action at the bottom of the card.
title
ReactNode
Card title. A string also names the stat for screen readers.
description
ReactNode
A line under the title.
unit
ReactNode
Small unit or context under the number, e.g. "active teams".
loading
boolean
Show the loading state.
error
string | null
An error message; shows the error state.
density
Density
"comfortable" (default) or "compact".
className
string
Classes on the card.
palette
"theme" | "shadcn"
"theme" (default) or "shadcn" to use your --chart-N colours.
trendHeight
number
Sparkline height in px.
| Prop | Type | Description |
|---|---|---|
| value* | number | null | The number. null or undefined shows the empty state. |
| previous | number | null | The comparison value, e.g. last period. |
| previousLabel | string | What the comparison is, e.g. "last month". |
| target | number | null | A goal. Adds a meter showing progress toward it. |
| trend | (number | null)[] | Recent values, oldest first, for the sparkline. Missing values break the line. |
| polarity | "up" | "down" | "up" when a rise is good (default), "down" for costs, churn, latency. |
| valueFormatter | (value: number) => string | Formats the number, change and target. |
| motion | MotionPreference | "full" (default), "subtle" or "off". Reduced-motion settings always win. |
| eyebrow | ReactNode | Small label above the title. |
| footer | ReactNode | A line or action at the bottom of the card. |
| title | ReactNode | Card title. A string also names the stat for screen readers. |
| description | ReactNode | A line under the title. |
| unit | ReactNode | Small unit or context under the number, e.g. "active teams". |
| loading | boolean | Show the loading state. |
| error | string | null | An error message; shows the error state. |
| density | Density | "comfortable" (default) or "compact". |
| className | string | Classes on the card. |
| palette | "theme" | "shadcn" | "theme" (default) or "shadcn" to use your --chart-N colours. |
| trendHeight | number | Sparkline height in px. |
Props every chart shares (2): data, config, header, states, legend, tooltip, formatting, motion and selection
locale
string
BCP 47 locale. Defaults to "en-US" so server and client render the same text.
timeZone
string
IANA time zone for dates. Defaults to "UTC" so server and client agree.
| Prop | Type | Description |
|---|---|---|
| locale | string | BCP 47 locale. Defaults to "en-US" so server and client render the same text. |
| timeZone | string | IANA time zone for dates. Defaults to "UTC" so server and client agree. |
Accessibility, keyboard and motion
- Pointer
- Not interactive.
- Keyboard
- Not focusable: there's nothing to move between.
- Screen readers
- A labelled group: the value, its change in words and the target are read as one sentence.
- Motion
- The value rolls in digit by digit, the trend line draws, then the change fades in. With reduced motion it appears settled at once.