A tile's trend as a small line, rendered on the server and decorative unless named.

In a stat tile

A sparkline shows a figure's shape over time, small enough to sit beside the figure. Pass it to a StatTile as its trend, and it takes the end of the value's row, 96 by 32.

Example

Spending

$2,148.90

Up 18% from last month

Last 30 days

Follows the page theme and corners
import { Sparkline } from '@snapshot-ui/charts';
import { StatTile } from '@snapshot-ui/react';
import type { ReactElement } from 'react';
import { SPENDING } from './sparkline-data';

export default function SparklineTile(): ReactElement {
  return (
    <div className="tile-row">
      <StatTile
        label="Spending"
        value="$2,148.90"
        change={{ direction: 'up', label: 'Up 18% from last month' }}
        caption="Last 30 days"
        trend={<Sparkline data={SPENDING} />}
      />
    </div>
  );
}

Area and end point

The line is 2px of ink with round caps and joins.

  • End point: an 8px dot in a ring of the surface marks the last value. hasEndPoint={false} leaves it out.
  • Area: hasArea fills under the line with a 10% ink wash, down to the bottom of the box.
  • Flat series: when all values are equal, the line is flat at mid-height.

Example

Default

With area

No end point

Flat

Follows the page theme and corners
import { Sparkline } from '@snapshot-ui/charts';
import { Card, Eyebrow } from '@snapshot-ui/react';
import type { ReactElement } from 'react';
import { SPENDING } from './sparkline-data';

export default function SparklineVariants(): ReactElement {
  return (
    <div className="sample-column">
      <Card>
        <div className="stack">
          <div className="row spread">
            <Eyebrow>Default</Eyebrow>
            <Sparkline data={SPENDING} />
          </div>
          <div className="row spread">
            <Eyebrow>With area</Eyebrow>
            <Sparkline data={SPENDING} hasArea />
          </div>
          <div className="row spread">
            <Eyebrow>No end point</Eyebrow>
            <Sparkline data={SPENDING} hasEndPoint={false} />
          </div>
          <div className="row spread">
            <Eyebrow>Flat</Eyebrow>
            <Sparkline data={[64, 64, 64, 64, 64, 64, 64, 64, 64, 64]} />
          </div>
        </div>
      </Card>
    </div>
  );
}

Naming it

A sparkline is hidden from assistive technology by default, since the tile beside it says what it means. When it says something the tile does not, give it an aria-label, such as "Spending, last 30 days, rising", or an aria-labelledby. It then becomes one image with that name. A blank name is ignored, so it never becomes an unnamed image.

<Sparkline data={spending} aria-label="Spending, last 30 days, rising" />

Size

The default box is 96 by 32. Set a width and height with className or style, and the drawing stretches to fill it. The line stays 2px wide and the dot stays round, because the dot is drawn over the line. Nothing is measured, so the server's HTML is final.

<Sparkline data={spending} style={{ width: '100%', height: '3rem' }} />

Right to left

The oldest value is at the inline start and the newest at the inline end, which is the left under dir="rtl". The direction comes from the nearest dir="ltr" or dir="rtl" attribute, so a dir="ltr" region inside a right-to-left page draws left to right. Only that attribute sets --chart-direction, which the plot reads. Under dir="auto" or a CSS direction alone, the line and its end dot draw left to right.

On another surface

The ring around the end point uses --chart-surface, which is Lifted by default, the card a sparkline usually sits on. On the page itself, set --chart-surface: var(--color-canvas) on the sparkline or any ancestor, and every chart inside follows.

.overview-section {
  --chart-surface: var(--color-canvas);
}

Usage

pnpm add @snapshot-ui/charts @snapshot-ui/core

It needs the same 0.x minor of @snapshot-ui/core (0.10 for charts 0.2.1), whose styles.css draws it. Pass numbers, oldest first. The domain is their extent, not from zero, because a sparkline shows a shape, not a magnitude. It is static, so a server component renders it with no client JavaScript.

import { Sparkline } from '@snapshot-ui/charts';
import { StatTile } from '@snapshot-ui/react';

<StatTile
  label="Spending"
  value="$2,148.90"
  change={{ direction: 'up', label: 'Up 18% from last month' }}
  trend={<Sparkline data={spending} />}
/>;

Props

A Sparkline accepts every HTML element attribute on its root, a span.

aria-label
string

A name for assistive technology. Give it, or aria-labelledby, where no label or text is shown.

aria-labelledby
string

The id of an element that holds the name, such as a label shown elsewhere.

className
string

data
readonly number[]

The values, oldest first.

hasArea
boolean

Fills under the line with a 10% ink wash.

Default: false

hasEndPoint
boolean

Marks the last point with a dot.

Default: true

Accessibility

Hidden from assistive technology (aria-hidden) unless named. With an aria-label or aria-labelledby, it is one role="img" with that name, and the drawing inside stays hidden. It takes no focus and has no keys. In forced colors, the line and dot use the reader's text color, and the wash is dropped.

Design rules

What keeps sparklines in the system.

Put a sparkline beside the figure whose shape it shows.

Name it only when it says something the tile does not.

Never use a sparkline for a magnitude. It starts at its least value, not at zero.

Never draw a second series in a sparkline. That is a line chart.

Never make the reader hover a sparkline to learn what it says.

esc

↑ ↓ to move↵ to open