# Sparkline

A word-sized line for the margin of a table or beside a readout. It is an SVG that takes the size of the type around it and the ink of the place it sits in, so on a panel it is ink and on display glass it is the display’s light. The last value is marked with a dot seated in a faint ring, and a lamp lights the dot when the reading matters. The trend and the last value are said in words on the image’s label, so the line is a second sign and never the only one.

Kit part · Free · https://tactileui.dev/parts/sparkline

- Element: `<svg class="tui-sparkline" role="img">`
- Needs: `kit.css` only, no script ([how to install the kit](https://tactileui.dev/docs/installation#the-kit))
- Categories: Charts
- Finishes: Aluminium, Graphite, Oak, Walnut, Porcelain, Black, Daylight, Night, Paper, Phosphor, E-paper, AMOLED
- Volumes: Tactile, Quiet

## Variants

### Rising

```html
<span style="display:inline-flex;align-items:center;gap:10px">Bookings <svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="Bookings: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg></span>
```

### Falling

```html
<span style="display:inline-flex;align-items:center;gap:10px">Errors <svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="Errors: falling over 8 readings, last 38"><path class="area" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24 L80 24 L0 24 Z"/><path class="line" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24"/><circle class="seat" cx="80" cy="24" r="3.4"/><circle class="last" cx="80" cy="24" r="2.3"/></svg></span>
```

### Steady

```html
<span style="display:inline-flex;align-items:center;gap:10px">Load <svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="Load: steady over 8 readings, last 50%"><path class="area" d="M0 16 L11.4 4 L22.9 20 L34.3 0 L45.7 24 L57.1 8 L68.6 12 L80 16 L80 24 L0 24 Z"/><path class="line" d="M0 16 L11.4 4 L22.9 20 L34.3 0 L45.7 24 L57.1 8 L68.6 12 L80 16"/><circle class="seat" cx="80" cy="16" r="3.4"/><circle class="last" cx="80" cy="16" r="2.3"/></svg></span>
```

### Flat · no range at all

```html
<span style="display:inline-flex;align-items:center;gap:10px">Queue <svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="Queue: flat over 5 readings, last 4 ms"><path class="area" d="M0 12 L20 12 L40 12 L60 12 L80 12 L80 24 L0 24 Z"/><path class="line" d="M0 12 L20 12 L40 12 L60 12 L80 12"/><circle class="seat" cx="80" cy="12" r="3.4"/><circle class="last" cx="80" cy="12" r="2.3"/></svg></span>
```

### One reading

```html
<span style="display:inline-flex;align-items:center;gap:10px">First reading <svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: 1 reading, 61 ms"><circle class="seat" cx="40" cy="12" r="3.4"/><circle class="last" cx="40" cy="12" r="2.3"/></svg></span>
```

### Lit dot · green, amber, red

```html
<div style="width:min(300px,calc(100vw - 96px));text-align:left"><span style="display:inline-flex;align-items:center;gap:18px"><svg class="tui-sparkline" data-lamp="green" viewBox="-4 -4 88 32" role="img" aria-label="Errors: falling over 8 readings, last 38"><path class="area" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24 L80 24 L0 24 Z"/><path class="line" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24"/><circle class="seat" cx="80" cy="24" r="3.4"/><circle class="last" cx="80" cy="24" r="2.3"/></svg><svg class="tui-sparkline" data-lamp="amber" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg><svg class="tui-sparkline" data-lamp="red" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: rising over 6 readings, last 99 ms"><path class="area" d="M0 24 L16 22.3 L32 6.6 L48 1.4 L64 2.8 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L16 22.3 L32 6.6 L48 1.4 L64 2.8 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg></span></div>
```

### Sizes · --sm and --lg

```html
<div style="width:min(340px,calc(100vw - 96px));text-align:left"><span style="display:inline-flex;align-items:center;gap:18px"><svg class="tui-sparkline tui-sparkline--sm" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg><svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg><svg class="tui-sparkline tui-sparkline--lg" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg></span></div>
```

### On display glass · the display’s light

```html
<div class="tui-glass" style="display:inline-flex;align-items:center;gap:14px;font-size:14px"><span>p95</span><svg class="tui-sparkline" data-lamp="amber" viewBox="-4 -4 88 32" role="img" aria-label="p95 latency: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg><span style="font-variant-numeric:tabular-nums">76 ms</span></div>
```

### In a table row

```html
<div style="width:min(420px,calc(100vw - 96px));text-align:left"><div class="tui-table-wrap" style="width:100%"><table class="tui-table"><thead><tr><th scope="col">Service</th><th scope="col">Last 8 hours</th><th scope="col" class="is-num">p95</th></tr></thead><tbody><tr><td>Berth bookings</td><td><svg class="tui-sparkline" data-lamp="amber" viewBox="-4 -4 88 32" role="img" aria-label="Berth bookings: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg></td><td class="is-num">76 ms</td></tr><tr><td>Tide tables</td><td><svg class="tui-sparkline" data-lamp="green" viewBox="-4 -4 88 32" role="img" aria-label="Tide tables: falling over 8 readings, last 38 ms"><path class="area" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24 L80 24 L0 24 Z"/><path class="line" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24"/><circle class="seat" cx="80" cy="24" r="3.4"/><circle class="last" cx="80" cy="24" r="2.3"/></svg></td><td class="is-num">38 ms</td></tr><tr><td>Pilot dispatch</td><td><svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="Pilot dispatch: steady over 8 readings, last 50 ms"><path class="area" d="M0 16 L11.4 4 L22.9 20 L34.3 0 L45.7 24 L57.1 8 L68.6 12 L80 16 L80 24 L0 24 Z"/><path class="line" d="M0 16 L11.4 4 L22.9 20 L34.3 0 L45.7 24 L57.1 8 L68.6 12 L80 16"/><circle class="seat" cx="80" cy="16" r="3.4"/><circle class="last" cx="80" cy="16" r="2.3"/></svg></td><td class="is-num">50 ms</td></tr></tbody></table></div></div>
```

## Every state

- Rising
- Falling
- Steady
- Lit red

Hover, pressed and focus are forced with `.is-hover`, `.is-down` and `.is-focus`; checked and disabled are real.

## API

| Name | Kind | Values | What it does |
| - | - | - | - |
| svg.tui-sparkline[role="img"][aria-label] | element | named | The line. It is an image, so give it a name that says the trend and the last value, as sparklineSVG() does. |
| viewBox | attribute | "-4 -4 88 32" | The 80 by 24 box with a margin of 4 for the dot and the stroke. The size is the type’s: 5.5em wide. |
| .area · .line · .seat · .last | class | on the paths and circles | The shade under the line, the line, the faint ring and the dot at the last value. |
| [data-lamp] | attribute | green · amber · red · blue | Lights the dot in a lamp colour. Without it the dot is ink. The words on the label still say the news. |
| --sm · --lg | modifier | tui-sparkline--sm · --lg | Smaller beside body text in a dense table; larger beside a readout. |
| sparklineSVG(values, options) | function | pure | The whole SVG. Options: noun, unit, period, lamp, area, label (your own words instead of the ones it writes), class. |
| sparklineWords(values, options) | function | pure | The sentence: “p95 latency: rising over 8 readings, last 76 ms”. |
| sparklineTrend(values) · sparklinePoints(values) | function | pure | Rising, falling, steady (within a tenth of the range) or flat; and the points in the box. |

## Markup

```html
<!-- An image with a name that says the trend and the last value. The picture is a second sign. -->
<svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img"
     aria-label="p95 latency: rising over 8 readings, last 76 ms" data-lamp="amber">
  <path class="area" d="M0 17 L11.4 14.4 … L80 0 L80 24 L0 24 Z"/>
  <path class="line" d="M0 17 L11.4 14.4 … L80 0"/>
  <circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/>
</svg>

<!-- In a table cell, beside the figure it summarises: -->
<td>…svg…</td><td class="is-num">76 ms</td>
```

```js
import { sparklineSVG } from '/kit/kit.mjs';

cell.innerHTML = sparklineSVG([41, 44, 43, 52, 58, 61, 70, 76], {
  noun: 'p95 latency',   // what is measured, said first
  unit: 'ms',            // printed after the last value
  lamp: 'amber',         // optional: lights the dot
});
// aria-label: "p95 latency: rising over 8 readings, last 76 ms"
```

The demo on the page:

```html
<div class="tui-panel" style="width:min(100%,560px);display:grid;gap:16px;text-align:left"><div class="tui-panel__head" style="margin-bottom:0"><span class="tui-label">Services · Northwind</span></div><div data-sp-host><div class="tui-table-wrap" style="width:100%"><table class="tui-table"><thead><tr><th scope="col">Service</th><th scope="col">Last 8 hours</th><th scope="col" class="is-num">p95</th></tr></thead><tbody><tr><td>Berth bookings</td><td><svg class="tui-sparkline" data-lamp="amber" viewBox="-4 -4 88 32" role="img" aria-label="Berth bookings: rising over 8 readings, last 76 ms"><path class="area" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0 L80 24 L0 24 Z"/><path class="line" d="M0 24 L11.4 21.9 L22.9 22.6 L34.3 16.5 L45.7 12.3 L57.1 10.3 L68.6 4.1 L80 0"/><circle class="seat" cx="80" cy="0" r="3.4"/><circle class="last" cx="80" cy="0" r="2.3"/></svg></td><td class="is-num">76 ms</td></tr><tr><td>Tide tables</td><td><svg class="tui-sparkline" data-lamp="green" viewBox="-4 -4 88 32" role="img" aria-label="Tide tables: falling over 8 readings, last 38 ms"><path class="area" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24 L80 24 L0 24 Z"/><path class="line" d="M0 0 L11.4 1.8 L22.9 0.9 L34.3 8 L45.7 14.2 L57.1 17.8 L68.6 20 L80 24"/><circle class="seat" cx="80" cy="24" r="3.4"/><circle class="last" cx="80" cy="24" r="2.3"/></svg></td><td class="is-num">38 ms</td></tr><tr><td>Pilot dispatch</td><td><svg class="tui-sparkline" viewBox="-4 -4 88 32" role="img" aria-label="Pilot dispatch: steady over 8 readings, last 50 ms"><path class="area" d="M0 16 L11.4 4 L22.9 20 L34.3 0 L45.7 24 L57.1 8 L68.6 12 L80 16 L80 24 L0 24 Z"/><path class="line" d="M0 16 L11.4 4 L22.9 20 L34.3 0 L45.7 24 L57.1 8 L68.6 12 L80 16"/><circle class="seat" cx="80" cy="16" r="3.4"/><circle class="last" cx="80" cy="16" r="2.3"/></svg></td><td class="is-num">50 ms</td></tr></tbody></table></div></div><div style="display:flex;gap:12px;flex-wrap:wrap;align-items:center"><button class="tui-key tui-key--sm" type="button" data-sp-add>Add a reading</button><output class="tui-muted" style="font-size:var(--tui-t-small)" data-sp-out aria-live="polite"></output></div></div>
```

## Usage notes

Press Add a reading: the line takes in a new value, the dot moves to it and the label, which a screen reader reads, changes with it. The lamp on the first row is lit amber because the reading is high; the words in the last column say the same thing.

## Accessibility

- It is `role="img"` with an `aria-label` that says the trend and the last value in words: “p95 latency: rising over 8 readings, last 76 ms”. A screen reader user gets the news the picture carries.
- The picture is never the only sign. If the reading matters, say it in the cell beside the line (the figure, or a status with a lamp and a word), as the demo does.
- The line, the dot and the ring are 3:1 or better against the panel and against glass in every finish. A lit dot is a lamp colour with the figure beside it, never a colour on its own.
- In forced colours the line is the text colour and the dot is the highlight colour. Nothing moves, so reduced motion changes nothing.
- It is small enough to sit in a table cell and never makes the page scroll sideways at 390px.

## How it’s built

Plain SVG, drawn by one short function that scales the readings into an 80 by 24 box and writes a path, a shade, a ring and a dot. The size is in `em`, so it grows with the type it is set beside, and the ink is `--tui-ink`, so on display glass it is the display’s light without a rule of its own. There is no script to load: the markup is the part.

## Rules

Put the shape of the last few readings in the margin of a table, with the last one marked and the news said in words.

The full rules are in `sparkline.rules.md` in the brain, which ships with the Kit.

## Related parts

- [Plot](https://tactileui.dev/parts/plot): Line charts drawn as light on glass, or as ink on a panel: gridlines faint, two traces at most, a red line for now.
- [Readout](https://tactileui.dev/parts/readout): A printed label over a value: key figures, with the unit small and the change in words.
- [Table](https://tactileui.dev/parts/table): Rows of data with printed column labels, figures right-aligned in columns, and status in lamps with words.
