Skip to content
Nizivo UI

Metric

A label, a number and its change, the block Figma draws in both the KPI tile and the Revenue card. It takes the loading, empty and error contract, and keeps its box in all four states.

Server component, no client JS

Import

import { Metric } from '@nizivo/react/metric';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css and @nizivo/react/css/delta.css and @nizivo/react/css/inline-error.css and @nizivo/react/css/number-value.css and @nizivo/react/css/skeleton.css
import '@nizivo/react/css/metric.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. A chart in its chart slot ships what its own module ships. 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 it shares with KpiTile, TrendCard and RankedList.

Examples

Basic

Total sales
$48,290
+12.4%vs last week
Refunds
$1,290
+8%vs last month
Total sales
$123,307.40
+18.2%
import type { JSX } from 'react';
import { Delta } from '@nizivo/react/delta';
import { Metric } from '@nizivo/react/metric';

const USD = { style: 'currency', currency: 'USD', maximumFractionDigits: 0 } as const;

export function MetricExample(): JSX.Element {
  return (
    <div>
      <Metric
        label="Total sales"
        value={48290}
        format={USD}
        delta={0.124}
        comparison="vs last week"
      />
      {/* A rise in refunds is bad news: pass your own Delta for the tone */}
      <Metric
        label="Refunds"
        value={1290}
        format={USD}
        delta={<Delta value={0.08} tone="critical" />}
        comparison="vs last month"
      />
      <Metric
        size="display"
        label="Total sales"
        value={123307.4}
        format={{ style: 'currency', currency: 'USD', minimumFractionDigits: 2 }}
        delta={0.182}
      />
    </div>
  );
}

States

The four statuses (§16.5): the same box in each.

Orders
Loading Orders
Orders
No data
Orders
Could not load Orders
Orders
1,284
-3.1%vs last week
import type { JSX } from 'react';
import { Metric } from '@nizivo/react/metric';

export function MetricStatesExample(): JSX.Element {
  return (
    <div>
      <Metric label="Orders" status="loading" comparison="vs last week" />
      <Metric label="Orders" value={null} comparison="vs last week" />
      <Metric label="Orders" status="error" comparison="vs last week" />
      <Metric label="Orders" value={1284} delta={-0.031} comparison="vs last week" pending />
    </div>
  );
}

Props

Server component Renders data-slot="metric" with the class nz-metric. Props: MetricProps. Source: src/metric/metric.tsx.

NameTypeDefaultDescription
chartReactNode–

A small chart at the end of the value row, for example a Sparkline; shown while ready. Its box is at most the row's (KpiTile draws it at 88 × 28, Figma's tile).

comparisonReactNode–

Visible text after the delta, for example "vs last week".

From MetricDataProps.

deltanumber | ReactElement–

The change. A number renders <Delta value={delta} locale={locale} /> (a fraction: 0.124 is "+12.4%"); pass your own <Delta … /> element for another format, a tone or an icon.

From MetricDataProps.

emptyReactNode–

Replaces the "—" of the empty state.

From MetricDataProps.

errorReactNode–

Replaces the InlineError of the error state, for example one with a Retry action.

From MetricDataProps.

formatIntl.NumberFormatOptions{}

Intl.NumberFormat options for the value.

From MetricDataProps.

labelrequiredReactNode–

The name of the number, for example "Total sales". Also names the status texts.

From MetricDataProps.

labelIdstring–

The id of the label element, for an enclosing group's aria-labelledby (KpiTile sets it).

labelsPartial<MetricLabels>–

From MetricDataProps.

localestring'en-US'

BCP 47 tag for the value and a numeric delta.

From MetricDataProps.

pendingboolean–

A refresh is in flight while the value shows: data-pending and aria-busy.

From MetricDataProps.

renderRenderProp<MetricState>–
reserveChangeboolean–

Keep the change row's height when there is no delta and no comparison, so the box is the same whatever a fallback passes (KpiTile and TrendCard set it: Figma's tile and card always have it).

sizeMetricSize
"default""display"
'default'
statusDataStatus
"ready""loading""empty""error"
'ready'

§16.5 lifecycle.

From MetricDataProps.

valuenumber | null–

The number. null or undefined (or NaN) with status="ready" renders the empty state.

From MetricDataProps.

  • Also takes every attribute of <div> except children. (Omit<ComponentPropsWithRef<"div">, "children">)

render takes an element, or, in client code, a function of the props and this state (MetricState):

NameTypeDefaultDescription
pendingrequiredboolean–
sizerequiredMetricSize
"default""display"
–
statusrequiredDataStatus
"ready""loading""empty""error"
–

The status as rendered: 'empty' when a ready metric has no value.

Other exports

MetricDataProps type

import type { MetricDataProps } from '@nizivo/react/metric'

The value and status props Metric, KpiTile and TrendCard share.

NameTypeDefaultDescription
comparisonReactNode–

Visible text after the delta, for example "vs last week".

deltanumber | ReactElement–

The change. A number renders <Delta value={delta} locale={locale} /> (a fraction: 0.124 is "+12.4%"); pass your own <Delta … /> element for another format, a tone or an icon.

emptyReactNode–

Replaces the "—" of the empty state.

errorReactNode–

Replaces the InlineError of the error state, for example one with a Retry action.

formatIntl.NumberFormatOptions{}

Intl.NumberFormat options for the value.

labelrequiredReactNode–

The name of the number, for example "Total sales". Also names the status texts.

labelsPartial<MetricLabels>–
localestring'en-US'

BCP 47 tag for the value and a numeric delta.

pendingboolean–

A refresh is in flight while the value shows: data-pending and aria-busy.

statusDataStatus
"ready""loading""empty""error"
'ready'

§16.5 lifecycle.

valuenumber | null–

The number. null or undefined (or NaN) with status="ready" renders the empty state.

MetricLabels type

import type { MetricLabels } from '@nizivo/react/metric'

Strings Metric renders (§16.4), all visually hidden or replaceable by a slot. {label} is replaced by the label prop.

NameTypeDefaultDescription
emptyrequiredstring'No data'

Read after the "—" when there is no value and no empty slot.

errorrequiredstring'Could not load {label}'

The InlineError message when loading failed and there is no error slot.

loadingrequiredstring'Loading {label}'

Static text while status="loading" (§16.5: aria-busy plus this, no live region).

MetricProps type

import type { MetricProps } from '@nizivo/react/metric'

The props of Metric, listed above.

MetricSize type

import type { MetricSize } from '@nizivo/react/metric'

default: Numeric/KPI, the change on its own row (KPI Tile). display: Numeric/Display, the change beside the number (Revenue Card).

type MetricSize = "default" | "display"

MetricState type

import type { MetricState } from '@nizivo/react/metric'

The render state of Metric, listed above.

metricLabels constant

import { metricLabels } from '@nizivo/react/metric'

English defaults of Metric's strings; KpiTile and TrendCard use them too.

const metricLabels: MetricLabels

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
metric
.nz-metric
Metric
root (takes render)
  • data-size: "default""display" ← size
    The size prop; values in each component manifest
metric-change
.nz-metric-change
Metric
inner element (CSS only)
none
metric-chart
.nz-metric-chart
Metric
inner element (CSS only)
none
metric-comparison
.nz-metric-comparison
Metric
inner element (CSS only)
none
metric-empty
.nz-metric-empty
Metric
inner element (CSS only)
none
metric-label
.nz-metric-label
Metric
inner element (CSS only)
none
metric-value-row
.nz-metric-value-row
Metric
inner element (CSS only)
none

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.

HookDefaultRead as
--nz-metric-chart-max-block-size1.75rem
  • --_nz-metric-chart-block on .nz-metric-chart
--nz-metric-chart-max-inline-size5.5rem
  • --_nz-metric-chart-inline on .nz-metric-chart
--nz-metric-gap
  • default: var(--nz-space-4)
  • data-size="display": var(--nz-space-2)
  • gap on .nz-metric

Layers: nz.components. Classes: .nz-inline-error, .nz-inline-error-message, .nz-metric, .nz-metric-change, .nz-metric-change-skeleton, .nz-metric-chart, .nz-metric-comparison, .nz-metric-empty, .nz-metric-label, .nz-metric-value, .nz-metric-value-row, .nz-metric-value-skeleton.

Tokens this stylesheet reads (22)

--nz-font-body-m, --nz-font-label-m, --nz-font-label-m-strong-font-size, --nz-font-label-m-strong-line-height, --nz-font-numeric-display, --nz-font-numeric-display-font-size, --nz-font-numeric-display-line-height, --nz-font-numeric-kpi, --nz-font-numeric-kpi-font-size, --nz-font-numeric-kpi-line-height, --nz-radius-full, --nz-space-1, --nz-space-2, --nz-space-3, --nz-space-4, --nz-text-primary, --nz-text-secondary, --nz-text-tertiary, --nz-tracking-body-m, --nz-tracking-label-m, --nz-tracking-numeric-display, --nz-tracking-numeric-kpi

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: none
  • Ghost masters: none

On this page