Data
Sparkline, BarChart & LineChart
Change over time and magnitude across categories, with the mark specs, the legend, the tooltip and the table view already decided.
import { Sparkline, BarChart, LineChart, ChartFrame } from '@anomalia/ui'; Notes
- One series is ink, not a hue. Colour encodes *identity*, so a chart with nothing to tell apart has no reason to spend it — which is also what keeps a monochrome system monochrome until a stacked bar genuinely needs six colours.
- The six categorical slots are a validated set, not a taste call: checked for the lightness band, the chroma floor, adjacent-pair separation under deuteranopia, protanopia and tritanopia, and normal-vision separation. Worst adjacent CVD ΔE 9.1 light / 8.4 dark against a target of 8. **The order is the safety mechanism** — reassigning a slot voids the guarantee.
- Colour follows the entity, never its rank. Filtering a series out must not repaint the survivors, or a reader who learned "Instagram is blue" has been misled.
- There is no dual-axis prop and there will not be one. Two y-scales make the alignment between them arbitrary, so the chart invents a correlation that is not in the data — the single most common way a dashboard chart lies. Two measures of different magnitude are two charts, or both indexed to 100 at t0.
- Bars cap at 24px and never fill their band; they are rounded at the data end and square at the baseline, so a stack reads as one bar growing out of the axis. A 2px surface gap does the separating — never a stroke, which is ink that is not data.
- A
nullbreaks a line rather than being interpolated across. Drawing straight through missing data is a claim about data that does not exist. - Every multi-series chart ships a legend and a table view. That is what makes colour a redundant channel rather than the only one — and it is the condition under which a light-mode hue below 3:1 is legitimate as a *mark*.
- Hover is a crosshair on lines and a whole-column highlight on bars, because the comparison is across series at one x, not one dot. Emphasis dims the others rather than tinting the one, so the legend keeps matching.
- Axis ticks land on round numbers via
niceDomain, andcompactonly abbreviates past a thousand — "0.9K" is worse than 900 in every way.
Examples
Sparkline
A sparkline answers one question — which way is this going — at the size of a word. No axes, no legend, no tooltip: the moment an exact value matters, it is the wrong chart.
Reach
+18%184.2k
Failed jobs
+3131
Inline
A sparkline also works at line height, next to the number it belongs to.
4.71%
Bars
Bars cap at 24px and never fill their band — the leftover is air. Rounded at the data end only, square at the baseline, so a stack reads as one bar growing out of the axis. Hover dims the others rather than tinting the one, so the legend keeps matching.
Posts published by channel
- TikTok
Line
A crosshair rather than per-point hover: the pointer maps to the nearest column and reads every series at once, which is the comparison the chart exists for. Nulls break the line instead of being interpolated across.
Reach by channel
- TikTok
Engagement rate
API
LineChart
| Prop | Type | Default | Description |
|---|---|---|---|
series | Series[] | — | `{ id, label, values, color? }`. `id` is the identity colour follows. |
labels | string[] | — | One per x position. Ticks thin to fit; the table keeps them all. |
area | boolean | false | A 10% wash under the line. Single series only — stacked washes read as a colour nobody chose. |
zero | boolean | true | Include zero in the domain. Turn it off for a rate or an index. |
endLabels | boolean | true | The final value beside each line — the selective label. |
BarChart
| Prop | Type | Default | Description |
|---|---|---|---|
labels / series | string[] / Series[] | — | One bar per label; several series stack. |
showValues | boolean | false | The total on each cap, and only when the bar is wide enough for it. |
max | number | — | Fixed ceiling. The floor is always zero. |
Shared
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Names the chart for assistive tech and captions the table. |
tableView | boolean | true | The WCAG-clean twin. Turn it off only if you render your own. |
format | (n) => string | compact | Axis, labels and tooltip. |
toolbar | Snippet | — | Controls beside the title — a range picker, a series toggle. |
Every component also forwards the native attributes of its root element, plus class, so anything not listed here still works.