KPI
A key performance indicator card displaying a metric value with trend chip, sparkline chart, and contextual details.
Usage
Anatomy
Import the KPI component and access all parts using dot notation.
import { KPI } from "@blakeui/pro-react";
<KPI>
<KPI.Header>
<KPI.Icon />
<KPI.Title />
</KPI.Header>
<KPI.Actions />
<KPI.Content>
<KPI.Value />
<KPI.Trend />
<KPI.Progress />
</KPI.Content>
<KPI.Chart />
<KPI.Separator />
<KPI.Footer />
</KPI>;With Actions
With Chart Bottom
With Chart Inline
Only a chart that is a direct child of KPI goes full-bleed; nesting it inside KPI.Content keeps it in the value row, where it fills the grid's trailing auto column and needs an explicit width.
With Footer
With Icon
With Progress
CSS Classes
Base Classes
.kpi— The card shell. Relative, flex column,gap: 0,padding: --spacing * 4,border-radius: --radius * 2. Rendered on top of the@blakeui/reactCard, whose default gap thegap: 0neutralises so KPI can space its parts with margins instead.
Element Classes
.kpi__header— Top row. Flex, centred,gap: --spacing * 2,margin-bottom: --spacing * 1..kpi__content— The value row.grid-template-columns: 1fr auto, items centred,column-gap: --spacing * 2,flex: 1— so the value takes the free space and the trend or chart sits in the trailing column..kpi__icon— Status tile.--spacing * 8square,border-radius: --radius * 1, centred, and it sizes its ownsvgto--spacing * 4..kpi__actions— Absolutely positioned, insetcalc(--spacing * 4 - --spacing * 1.5)from the top-right so the ghost button's own padding lines its glyph up with the card padding..kpi__title—0.875rem/1.25rem,font-weight: 500,color: --muted. Renders as adt..kpi__value—1.5rem/2rem,font-weight: 600,letter-spacing: -0.025em,color: --foreground. Renders as add..kpi__trend—flex-shrink: 0, so the chip never compresses when the value is long..kpi__progress— Spans the whole value row (grid-column: 1 / -1) and adds--spacing * 1above, dropping below the value rather than beside it..kpi__chart— Sparkline container.overflow: hiddenplus a horizontalmask-imagethat fades to transparent over--kpi-chart-fadeat each edge..kpi > .kpi__chart— Full-bleed treatment, applied only when the chart is a direct child of the root:margin-top: --spacing * 2, negative inline and bottom margins of--spacing * 4, and the two bottom corners rounded to--radius * 2. A chart nested anywhere else keeps the mask and nothing else..kpi > .kpi__chart:has(+ .kpi__separator, + .kpi__footer)— Drops the bottom bleed and the corner rounding when a separator or footer follows the chart..kpi__separator—width: calc(100% + --spacing * 8)with--spacing * -4inline margins, so the rule reaches both card edges through the padding..kpi__footer—margin-bottom: --spacing * -1..kpi__separator + .kpi__footer— Removes the footer's top margin when a separator already provides the gap.
Data Attributes
[data-status="success"]on.kpi__icon—--successat 10% for the tile,--successfor the glyph.[data-status="warning"]on.kpi__icon—--warningat 10% for the tile,--warningfor the glyph.[data-status="danger"]on.kpi__icon—--dangerat 10% for the tile,--dangerfor the glyph.[data-slot]— Eleven of the twelve parts carry one (kpi,kpi-header,kpi-content,kpi-icon,kpi-title,kpi-value,kpi-progress,kpi-actions,kpi-chart,kpi-separator,kpi-footer), so a part can be targeted without depending on its BEM class.[data-trend="up"]/[data-trend="down"]/[data-trend="neutral"]on.kpi__trend— Set by the underlying Chip.KPI.Trendis the one part with nokpi-trendslot: the Chip's owndata-slot="chip"wins, so target the chip by.kpi__trendor bydata-trendinstead.
CSS Variables
--kpi-chart-fade— How far the sparkline mask fades in from each horizontal edge. Declared on.kpi__chart; default10%.
API Reference
KPI
The root. Renders the @blakeui/react Card and supplies the slot context every part reads.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The parts to compose. KPI.Chart is treated specially: as a direct child it goes full-bleed to the card edges, nested it stays inline. |
className | string | — | Merged onto the .kpi root. Use it to flip the inherited Card elevation, e.g. border-separator border shadow-none for a flat tile. |
Also accepts every BlakeUI Card prop.
KPI.Header
The top row — icon and title. Sits above KPI.Content, and is the only part KPI.Actions visually overlaps.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Typically a KPI.Icon followed by a KPI.Title. |
className | string | — | Merged onto .kpi__header. |
Also accepts every native div attribute.
KPI.Content
The value row. A two-column grid (1fr auto) that pairs the value with whatever sits beside it.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | A KPI.Value plus one trailing part — a KPI.Trend or an inline KPI.Chart. A KPI.Progress spans both columns instead, dropping onto its own line. A third in-flow child wraps to an implicit second row. |
className | string | — | Merged onto .kpi__content. |
Also accepts every native div attribute.
KPI.Icon
The tinted glyph tile. Sizes any svg inside it, so an icon needs no size class of its own.
| Prop | Type | Default | Description |
|---|---|---|---|
status | "success" | "warning" | "danger" | — | Sets data-status, which tints the tile with the matching token at 10% and colours the glyph with it at full strength. Omitted, the tile is untinted and the glyph inherits currentColor. |
children | ReactNode | — | The glyph. Required. |
className | string | — | Merged onto .kpi__icon. |
Also accepts every native div attribute.
KPI.Title
The metric label, rendered as a dt.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The label text. Required. |
className | string | — | Merged onto .kpi__title. |
Also accepts every native dt attribute.
KPI.Value
The formatted number, rendered as a dd. Wraps NumberValue, so formatting is locale-aware and driven entirely by props.
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | The number to format. Required. |
children | (formatted: string) => ReactNode | — | Render function receiving the formatted string, for appending a unit or wrapping part of the value in its own markup. Without it the formatted string renders as-is. |
style | "decimal" | "currency" | "percent" | "unit" | "decimal" | Formatting style. currency also needs currency; unit also needs unit. A percent value is a fraction, so 0.42 renders as 42%. |
notation | "standard" | "compact" | "scientific" | "engineering" | "standard" | compact is what turns 98000 into 98K. |
currency | string | — | ISO 4217 code, e.g. USD. Required by style="currency". |
unit | string | — | Sanctioned unit identifier, e.g. celsius. Required by style="unit". |
minimumFractionDigits / maximumFractionDigits | number | — | Clamp the decimals. Both follow the Intl defaults for the chosen style. |
signDisplay | "auto" | "always" | "never" | "exceptZero" | "auto" | exceptZero forces a leading + on positive values. |
locale | string | — | Overrides the locale. Defaults to the ambient React Aria locale, so leave it unset to follow the app. |
formatOptions | NumberFormatOptions | — | An escape hatch that replaces every option above rather than merging with them. |
className | string | — | Merged onto .kpi__value. |
KPI.Trend
The delta badge. Wraps TrendChip, whose direction drives both the caret and the colour.
| Prop | Type | Default | Description |
|---|---|---|---|
trend | "up" | "down" | "neutral" | "up" | Direction — not sentiment. up is a success caret, down a danger one, and neutral drops the caret for a default-coloured chip. |
children | ReactNode | — | The delta text. Required. Accepts TrendChip.Prefix, TrendChip.Suffix, and TrendChip.Indicator alongside it. |
variant | "soft" | "primary" | "secondary" | "tertiary" | "soft" | Chip fill treatment. |
size | "sm" | "md" | "lg" | "sm" | Chip size, which also sizes the caret. |
className | string | — | Merged onto .kpi__trend. |
KPI.Progress
A full-width bar beneath the value. Wraps the @blakeui/react ProgressBar at size sm, whose fill transitions over 300ms when the value changes and holds still under prefers-reduced-motion.
| Prop | Type | Default | Description |
|---|---|---|---|
value | number | — | Percentage from 0 to 100. Required, and clamped to that range — it is independent of KPI.Value, so a percent-formatted value has to be passed to both. |
status | "success" | "warning" | "danger" | "success" | Fill colour, mapped onto the ProgressBar colour of the same name. |
className | string | — | Merged onto .kpi__progress, the wrapper — not onto the bar inside it. |
Also accepts every native div attribute.
KPI.Actions
The corner button. Wraps the @blakeui/react Button as a small ghost icon-only button, absolutely positioned over the header.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Three-dot glyph | Replaces the default glyph. A replacement is not sized for you, so give it size-4 to match. |
aria-label | string | — | Pass one. The button is icon-only and the component supplies no fallback name, so without it the control is announced unlabelled. |
onPress | (e: PressEvent) => void | — | Press handler. For a menu, use the button as a Menu trigger instead. |
className | string | — | Forwarded to the Button, not to the .kpi__actions wrapper — which is the one part whose positioning class cannot be overridden from the outside. |
Also accepts every BlakeUI Button prop.
KPI.Chart
The sparkline. Full-bleed as a direct child of KPI, inline anywhere else, and edge-masked in both cases.
| Prop | Type | Default | Description |
|---|---|---|---|
data | Record<string, number | string>[] | — | One object per point, each carrying a numeric field named by dataKey. Required. |
dataKey | string | "value" | Which field of each object supplies the Y value. |
color | string | "currentColor" | Stroke colour, and the gradient's colour when fillColor is unset. Takes a var(--chart-1) reference. |
fillColor | string | — | Overrides the gradient colour independently of the stroke. The gradient itself always runs 20% down to 2% opacity. |
height | number | 80 | Height in pixels. The width is always fluid, so an inline chart also needs a width from className. |
strokeWidth | number | 2 | Line thickness. |
className | string | — | Merged onto .kpi__chart. |
Also accepts every native div attribute.
KPI.Separator
An edge-to-edge rule. Wraps the @blakeui/react Separator and widens it back through the card padding.
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Only horizontal is meaningful here — the full-bleed width comes from the KPI class, which assumes a horizontal rule. |
className | string | — | Merged onto .kpi__separator. |
Also accepts every BlakeUI Separator prop.
KPI.Footer
The bottom strip, for a link or a supporting detail.
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The footer content. Required. |
className | string | — | Merged onto .kpi__footer. |
Also accepts every native div attribute.