KPI
One number and what it is doing: its change, its shape over time, its progress to a target.
Use it for a number someone checks, with whatever says how it is doing: the change since last time, the shape of it over a period, how far it is towards a target.
The number comes first. The trend, the chart and the bar are all small on purpose, and none of them can be read to a value.
For a chart someone needs to read values from, use a chart with an axis. For one bare figure with a label, a KpiTitle and a KpiValue are enough.
Installation
Copy the folder into components/ui, where you can edit it. It needs the cn helper and the theme's info, success and warning colours.
components/ui/kpi/
├── Kpi.vue
├── KpiHeader.vue … KpiGroup.vue
└── index.tsUsage
<script setup lang="ts">
import { Kpi, KpiTitle, KpiTrend, KpiValue } from "@/components/ui/kpi";
</script>
<template>
<Kpi>
<KpiTitle>Subscribers</KpiTitle>
<KpiValue>18,240</KpiValue>
<KpiTrend :value="6.4" caption="this month" />
</Kpi>
</template>Composition
<Kpi>
<KpiHeader>
<KpiIcon />
<KpiTitle />
<KpiActions />
</KpiHeader>
<KpiContent>
<KpiStat>
<KpiValue />
<KpiTrend />
</KpiStat>
<KpiChart />
</KpiContent>
<KpiProgress />
<KpiFooter />
</Kpi>- KpiHeader: the row over the number. A title in it takes the room between the icon and the actions.
- KpiIcon: a small tile for an icon. tone colours it as good or bad news.
- KpiTitle: what the number measures.
- KpiActions: whatever belongs at the end of the header: a period, a trend badge, a button.
- KpiContent: the row the number is in. layout="inline" is for a chart beside it.
- KpiStat: title, value and trend stacked as one block, for a row with a chart at its other end.
- KpiValue: the number.
- KpiTrend: the change, given as a number. It writes the sign and picks the colour.
- KpiChart: a sparkline of a list of numbers. inline gives it a fixed box, filled a wash under the line.
- KpiProgress: a bar towards a target, with a label and the percentage over it.
- KpiFooter: a quiet line under everything.
- KpiSeparator: a rule between two parts of one card.
- KpiGroup: several metrics as one panel, side by side or stacked, with a rule between each and the next. surface draws it as a card of its own.
A card of its own
surface draws the metric as a card. The trend is a badge in the header, and the chart runs the width of the card under the number with a wash beneath the line.
Towards a target
KpiProgress takes a value and what it is out of. KpiIcon takes a tone, so the tile can agree with the news beside it.
Several as one panel
KpiGroup puts a rule between metrics and shares the width between them. Without a header each metric is a title, a value and a trend.
API Reference
Kpi
KpiIcon
KpiContent
KpiTrend
KpiChart
KpiProgress
KpiGroup
Every part also takes the attributes of the element it renders, and a class.
Notes
Trend colours
KpiTrend is drawn in the success colour when the number moved the good way, in the destructive colour when it moved the bad way, and in the muted colour when it did not move. Up is good unless you say otherwise: pass good-direction="down" for a metric where less is better, or "none" for one where neither is.
threshold is the size of change that still counts as none. With :threshold="0.5", a change of 0.3 is drawn flat.
Writing the change
The change is written as a signed percentage with one decimal. format is given the value and returns the text, for a change in another unit. caption adds quiet words after it and is read out with it.
The chart
data is a list of numbers, oldest first. The line is scaled between the lowest and highest of them, so it shows the shape of the change and says nothing about its size. That is why it has no axis.
inline fixes the chart at 128 by 56 pixels. In a column of cards with titles of different lengths, the charts are then all one width and line up down the right-hand edge.
Colour
color on KpiChart and KpiProgress names one of the theme's roles and defaults to primary.
In a group
KpiGroup pads its children on the sides that face a rule. Put Kpi elements straight inside it. In a horizontal group the metrics share the width equally, so keep titles to a word or two, or stack them with orientation="vertical".
Server rendering
KPI holds no state, so it renders the same on the server as in the browser and adds no work after hydration.