KpiTile
One number, its change and its shape, on Card's surface. Tint a row of related KPIs with tone, which no longer follows the trend. The Suspense fallback is the same tile with status="loading".
Import
import { KpiTile } from '@nizivo/react/kpi-tile';
// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css and @nizivo/react/css/card.css and @nizivo/react/css/delta.css and @nizivo/react/css/inline-error.css and @nizivo/react/css/metric.css and @nizivo/react/css/number-value.css and @nizivo/react/css/skeleton.css
import '@nizivo/react/css/kpi-tile.css';Static or interactive
Server. It ships no client JavaScript when a Server Component renders it, in every Next.js build
mode; its code is bundled only when a client component (a 'use client' file) imports it. The chart arrives as an element (chart={<Sparkline … />} from @nizivo/charts, which ships
no client code either); @nizivo/react never imports @nizivo/charts. How to
choose.
In a client app (a Vite or React Router single-page app, or a 'use client' file) it is an ordinary React component: event handlers, refs and state work as usual. In a client app.
See Dashboard for the status contract, a Suspense example and charts through slots.
Tones
tone is surface (the default), brand or accent: Card's surfaces, chosen for the row, not
from the sign of the change.
- On
brandandaccentthe Delta pill isbg/surfacerather than Figma'sbg/success-subtle, which is the same green-50 as thebrandtint and would show no fill. A deviation from Figma 04 (gap 4), chosen by the maintainer (M42); see Card. - In dark mode
brandandaccentare both green-950, so they look the same. That is Figma's design, followed for now (Figma 04 issue 5; M42). - The tile is a Card, so it declares
--nz-surface: a Sparkline inchartdraws its end-dot halo in the tile's colour, not as a white ring (Card).
Examples
Basic
Figma's four variants: the tint groups a row and no longer follows the trend.
import type { JSX } from 'react';
import { KpiTile } from '@nizivo/react/kpi-tile';
const USD = { style: 'currency', currency: 'USD', maximumFractionDigits: 0 } as const;
/**
* A stand-in for `<Sparkline data={series} label="…" />` from @nizivo/charts, which @nizivo/react
* never imports: any element fits the `chart` slot.
*/
function Shape({ d }: { d: string }): JSX.Element {
return (
<svg viewBox="0 0 88 28" width="88" height="28" aria-hidden="true" fill="none">
<path d={d} stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
</svg>
);
}
const UP = 'M1 22 L12 19 L23 21 L34 15 L45 17 L56 11 L67 12 L78 6 L87 4';
const DOWN = 'M1 6 L12 9 L23 7 L34 13 L45 11 L56 16 L67 15 L78 21 L87 23';
export function KpiTileExample(): JSX.Element {
return (
<div>
<KpiTile
label="Total sales"
value={48290}
format={USD}
delta={0.124}
comparison="vs last week"
chart={<Shape d={UP} />}
/>
<KpiTile
label="Conversion"
value={0.032}
format={{ style: 'percent', maximumFractionDigits: 1 }}
delta={-0.031}
comparison="vs last week"
chart={<Shape d={DOWN} />}
/>
<KpiTile
tone="brand"
label="Orders"
value={1284}
delta={0.124}
comparison="vs last week"
chart={<Shape d={UP} />}
/>
<KpiTile
tone="accent"
label="Returning rate"
value={0.284}
format={{ style: 'percent', maximumFractionDigits: 1 }}
delta={-0.031}
comparison="vs last week"
chart={<Shape d={DOWN} />}
/>
</div>
);
}
States
The four statuses (§16.5). The loading tile is also the Suspense fallback; the box is the same.
import type { JSX } from 'react';
import { KpiTile } from '@nizivo/react/kpi-tile';
const USD = { style: 'currency', currency: 'USD', maximumFractionDigits: 0 } as const;
export function KpiTileStatesExample(): JSX.Element {
return (
<div>
<KpiTile label="Total sales" status="loading" />
<KpiTile label="Total sales" value={null} />
<KpiTile label="Total sales" status="error" />
<KpiTile label="Total sales" value={48290} format={USD} delta={0.124} pending />
</div>
);
}
Props
One number, its change and its shape. A role="group" named by the label (not a landmark). The Suspense fallback is the same tile with status="loading": the box does not change (§16.5).
Server component Renders data-slot="kpi-tile" with the class nz-kpi-tile. Props: KpiTileProps. Source: src/kpi-tile/kpi-tile.tsx.
| Name | Type | Default | Description |
|---|---|---|---|
chart | ReactNode | – | A small chart beside the value, shown while ready, for example |
comparison | ReactNode | – | Visible text after the delta, for example "vs last week". From |
delta | number | ReactElement | – | The change. A number renders From |
empty | ReactNode | – | Replaces the "—" of the empty state. From |
error | ReactNode | – | Replaces the InlineError of the error state, for example one with a Retry From |
format | Intl.NumberFormatOptions | {} |
From |
labelrequired | ReactNode | – | The name of the number, for example "Total sales". Also names the status texts. From |
labels | Partial<MetricLabels> | – | From |
locale | string | 'en-US' | BCP 47 tag for the value and a numeric From |
pending | boolean | – | A refresh is in flight while the value shows: From |
render | RenderProp<KpiTileState> | – | |
status | DataStatus"ready""loading""empty""error" | 'ready' | §16.5 lifecycle. From |
tone | KpiTileTone"surface""brand""accent" | 'surface' | The surface; group a row of related KPIs with one tint. |
value | number | null | – | The number. From |
- Also takes every attribute of
<div>exceptchildren. (Omit<ComponentPropsWithRef<"div">, "children">)
render takes an element, or, in client code, a function of the props and this state (KpiTileState):
| Name | Type | Default | Description |
|---|---|---|---|
pendingrequired | boolean | – | |
statusrequired | DataStatus"ready""loading""empty""error" | – | The status as rendered: |
tonerequired | KpiTileTone"surface""brand""accent" | – |
Other exports
KpiTilePropstypeimport type { KpiTileProps } from '@nizivo/react/kpi-tile'The props of
KpiTile, listed above.KpiTileStatetypeimport type { KpiTileState } from '@nizivo/react/kpi-tile'The render state of
KpiTile, listed above.KpiTileTonetypeimport type { KpiTileTone } from '@nizivo/react/kpi-tile'Figma "Tone": Surface, or Tinted as
brandoraccent(Card's tones of the same names).type KpiTileTone = "surface" | "brand" | "accent"
Data attributes and slots
Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.
| Slot | Rendered by | Data attributes |
|---|---|---|
kpi-tile.nz-kpi-tile | KpiTileroot (takes render) |
|
CSS hooks
Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.
This stylesheet reads no public hook.
Layers: nz.components. Classes: .nz-card, .nz-kpi-tile, .nz-metric, .nz-metric-change.
Accessibility
Nothing in this component takes focus or keyboard input.
Keyboard
None.
Figma
Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.
- Canonical: Figma node
7275:13780 - Ghost masters: Figma node
752:380
Kbd
A keyboard shortcut drawn for both platforms, such as ⌘K and Ctrl+K; CSS shows the one for the current platform.
Menu
A menu of actions or links opened from a button, with groups, separators, shortcuts, a critical tone, and checkbox and radio items. For choosing a form value, use Select; for navigation between views, use TabNav.