Skip to content
Nizivo UI

TrendCard

A headline number with its change, a period control and a comparison chart, on Card's surface. Figma's Revenue card is one example of it. Every region is an element slot.

Server component, no client JS

Import

import { TrendCard } from '@nizivo/react/trend-card';

// 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/trend-card.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. Its slots render what you pass: a client Select in action ships its own code, and an AreaChart in chart ships the charts island. 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.

Tones

tone is Card's. On brand and accent the headline's Delta pill is bg/surface so it shows on the tint, and the card declares --nz-surface for the chart to read (Card).

Examples

Basic

The Revenue Card recipe (Figma 7275:13818): a docs example, not an export.

Total sales
$123,307.40
+18.2%
Oct 1 – Oct 30Sep 1 – Sep 30
import type { JSX } from 'react';
import { NativeSelect } from '@nizivo/react/native-select';
import { TrendCard } from '@nizivo/react/trend-card';

/**
 * Stand-ins for `<AreaChart … />` and `<Legend … />` from @nizivo/charts, which @nizivo/react never
 * imports: any element fits the slots.
 */
function Plot(): JSX.Element {
  return (
    <svg viewBox="0 0 720 280" width="100%" aria-hidden="true">
      <path
        d="M0 220 L80 190 L160 205 L240 150 L320 165 L400 120 L480 130 L560 80 L640 95 L720 60"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
      />
      <path
        d="M0 235 L80 225 L160 228 L240 200 L320 210 L400 185 L480 190 L560 160 L640 170 L720 150"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeDasharray="5 4"
        opacity="0.5"
      />
    </svg>
  );
}

export function TrendCardExample(): JSX.Element {
  return (
    <TrendCard
      label="Total sales"
      value={123307.4}
      format={{ style: 'currency', currency: 'USD', minimumFractionDigits: 2 }}
      delta={0.182}
      action={
        <NativeSelect aria-label="Period" defaultValue="30d" size="md">
          <option value="7d">Last 7 days</option>
          <option value="30d">Last 30 days</option>
          <option value="90d">Last 90 days</option>
        </NativeSelect>
      }
      chart={<Plot />}
      legend={
        <>
          <span>Oct 1 – Oct 30</span>
          <span>Sep 1 – Sep 30</span>
        </>
      }
    />
  );
}

Loading

Loading: the same card; the chart takes the same status in an app (ChartFrame keeps its box).

Total sales
Loading Total sales
import type { JSX } from 'react';
import { TrendCard } from '@nizivo/react/trend-card';

/**
 * Stand-ins for `<AreaChart … />` and `<Legend … />` from @nizivo/charts, which @nizivo/react never
 * imports: any element fits the slots.
 */
function Plot(): JSX.Element {
  return (
    <svg viewBox="0 0 720 280" width="100%" aria-hidden="true">
      <path
        d="M0 220 L80 190 L160 205 L240 150 L320 165 L400 120 L480 130 L560 80 L640 95 L720 60"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
      />
      <path
        d="M0 235 L80 225 L160 228 L240 200 L320 210 L400 185 L480 190 L560 160 L640 170 L720 150"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeDasharray="5 4"
        opacity="0.5"
      />
    </svg>
  );
}

export function TrendCardLoadingExample(): JSX.Element {
  return <TrendCard label="Total sales" status="loading" chart={<Plot />} />;
}

Props

A headline number with its change, a period control and a comparison chart. A role="group" named by the label. The status contract (§16.5) applies to the headline; the slots render as given.

Server component Renders data-slot="trend-card" with the class nz-trend-card. Props: TrendCardProps. Source: src/trend-card/trend-card.tsx.

NameTypeDefaultDescription
actionReactNode–

The control at the end of the header, for example the period Select or a SegmentedControl.

chartReactNode–

The chart, for example <AreaChart … /> from @nizivo/charts. Rendered in every status, so the box stays put: give the chart the same status (ChartFrame keeps its box in all four).

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.

footerReactNode–

A last row, for example a link to the report.

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.

labelsPartial<MetricLabels>–

From MetricDataProps.

legendReactNode–

The legend under the chart, for example <Legend items={…} />.

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<TrendCardState>–
statusDataStatus
"ready""loading""empty""error"
'ready'

§16.5 lifecycle.

From MetricDataProps.

toneCardTone
"surface""subtle""inverse""brand""accent"
'surface'

Card's tone; inverse scopes the inverse scheme.

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 (TrendCardState):

NameTypeDefaultDescription
pendingrequiredboolean–
statusrequiredDataStatus
"ready""loading""empty""error"
–

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

tonerequiredCardTone
"surface""subtle""inverse""brand""accent"
–

Other exports

TrendCardProps type

import type { TrendCardProps } from '@nizivo/react/trend-card'

The props of TrendCard, listed above.

TrendCardState type

import type { TrendCardState } from '@nizivo/react/trend-card'

The render state of TrendCard, listed above.

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
trend-card
.nz-trend-card
TrendCard
root (takes render)
  • data-nz-scheme: "inverse"
    Inverse surface scheme for the subtree
  • data-padding: "md"
    The padding prop, or the fixed padding of a part drawn on Card's surface, which has no padding prop; values in each component manifest (Card: sm, md; KpiTile: sm; TrendCard: md)
  • data-tone: "surface""subtle""inverse""brand""accent" ← tone
    The tone prop; values in each component manifest
trend-card-action
.nz-trend-card-action
TrendCard
inner element (CSS only)
none
trend-card-chart
.nz-trend-card-chart
TrendCard
inner element (CSS only)
none
trend-card-footer
.nz-trend-card-footer
TrendCard
inner element (CSS only)
none
trend-card-header
.nz-trend-card-header
TrendCard
inner element (CSS only)
none
trend-card-legend
.nz-trend-card-legend
TrendCard
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-trend-card-gap--nz-space-6
  • gap on .nz-card.nz-trend-card

Layers: nz.components. Classes: .nz-card, .nz-metric, .nz-metric-value-row, .nz-trend-card, .nz-trend-card-action, .nz-trend-card-chart, .nz-trend-card-footer, .nz-trend-card-header, .nz-trend-card-legend.

Tokens this stylesheet reads (7)

--nz-font-numeric-display-font-size, --nz-font-numeric-display-line-height, --nz-space-2, --nz-space-3, --nz-space-4, --nz-space-5, --nz-space-6

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.

On this page