KPI row
A dashboard's header row: key figures on one card, each with its change.
Installation
If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.
When to use
Use it
- As a dashboard's header row: the three to five numbers a page is about, the way Pipeline Inspection opens with open pipeline, closed won, win rate and average deal size.
- When each number means most next to its change against a period, like last quarter.
- When the row has to hold its shape while the numbers load.
Don't use it
- For one number on its own card, or your own arrangement of label, value and trend. Use Metric.
- For progress toward a target or quota. Use Gauge.
- For a list of values to compare with each other. Use Bar list or Data table.
Usage
import { KpiRow } from "@/components/wisty/kpi-row"<KpiRow
comparison="last quarter"
metrics={[
{
id: "renewals",
label: "Renewal ARR",
value: 2_140_000,
previous: 1_980_000,
},
{
id: "cycle",
label: "Average sales cycle",
value: 41,
previous: 47,
format: { style: "unit", unit: "day", unitDisplay: "long" },
isIncreasePositive: false,
},
]}
/>The block formats each number and derives its change as a percent of previous: "+8.1% vs last quarter". With a percent format the change is in points. When previous is 0 it's the difference itself.
Examples
Missing figures
Open pipeline has no `previous`, so it shows no change, and quota attainment's `value` is `null`, so it says No data.
Loading
With `loading`, every metric holds its shape with placeholders before the numbers arrive, and the labels stay readable.
API reference
KpiRow
| Prop | Type | Default | Description |
|---|---|---|---|
metrics* | KpiRowMetric[] | Two to five key figures, in reading order. | |
comparison | string | "last quarter" | The comparison period, as said after "vs". Default "last quarter". |
loading | boolean | false | Holds every metric's shape with placeholders while the numbers load. |
currency | string | "USD" | An ISO 4217 code for metrics with no format. Default "USD". |
locale | string | "en-US" | A BCP 47 locale for numbers. Default "en-US". |
Also takes every <div> (opens in a new tab) prop.
KpiRowMetrictype
One key figure.
| Member | Type | Default | Description |
|---|---|---|---|
id* | string | ||
label* | string | What's measured, in sentence case: "Open pipeline". | |
value* | number | null | The current value. null shows "No data" and no change. | |
previous | number | null | The comparison period's value. Shows the change against it. | |
format | Intl.NumberFormatOptions | How the value reads, as Intl.NumberFormat options. Default an amount in the block's currency, or a plain number without one. | |
isIncreasePositive | boolean | Whether a rise is good. Default true. Pass false for open cases, sales cycle, handle time, churn. |
SLDS mapping
Accessibility
- The card is a group named "Key metrics". Pass
aria-labelto name it for the page. - Direction is in the signed text. Whether a change is good shows in color only, so where that isn't obvious, make the label say it.
- While loading, each metric is busy and its value and change are placeholders. The labels stay readable.
Motion
- The loading placeholders pulse, and stop when the user asks for reduced motion.
Responsive behavior
- The card takes its width from its container, not its content, so give it one in a flex row.
- Its columns follow its own width, so a row never leaves one metric alone: four go one, two by two, then four across from 44rem; five go three over two, then five across from 55rem.
- A long label wraps. The value doesn't shrink.
Rules
- Pass numbers to
valueandprevious, never formatted strings, andnullfor a value you don't have, never 0. - Pass a percent as a fraction (0.318) with a percent
format, so its change reads in points. - Set
isIncreasePositive: falseon every metric where a fall is good, like open cases, sales cycle, handle time or churn. Never flip the sign to get a color. - Write
comparisonas a person would say it after "vs": "last quarter", "same week last year". - Pass amounts in one currency and set
currencyto match. Mixed currencies are unavailable (value: null), not added up. - Never pass
asChildorrender.
Related
- MetricShows one number with its name, a unit and a trend colored good or bad.
- GaugeShows one value against a maximum, as a dial, a ring, a bar or a row of dots.
- Bar listRanks labeled values with a bar under each on one scale, with shares of a total.
- Data tableShows records in a table that sorts, selects, runs row actions and loads more.