All documents

Charts

Four types, each ONE component configured by props — not a family of near duplicates to choose between. registry/components/brand/charts.tsx, built on Recharts through the shadcn chart.tsx primitive, both ported from the clients portal rather than written fresh.

ComponentForThe switches
Trend
A value over time
area, reference, legend, series[]
Bars
A value across categories
stacked, legend, series[]
Share
Parts of one whole
donut
Ranking
Which is biggest, and by how much
max, slot, onSelect, muted per row

Two shapes of input, and the difference is not an accident

Trend and Bars take data + x + series[] — a dataset, plus which field is the axis and which fields to plot. That is Recharts' own shape, and it is right when one row holds several series.

Ranking takes rows of { key, label, value } — rows already resolved, because a ranking has exactly one value per row and nothing to select from it.

The prop name is the tell: data is "here is a dataset, plot these fields"; rows is "here are the rows". Renaming one to match the other would hide a real difference in what the component needs.

Ranking is not a Recharts chart at all. Horizontal bars are divs with a width — the same call the sparkline makes. Mounting a chart library to lay out five rows costs a layout pass and an SVG for something CSS does exactly, and it would lose the thing that makes a ranking useful: the rows are real DOM, so they take a click, a hover and a link.

Five fixed hues, and a chart does NOT follow the brand

--chart-1--chart-5 are five hues chosen to be told apart, one set per theme. They were derived from the accent and the semantics until 2026-08-20, and that was wrong twice over:

  • It broke in the parent brand. iq's accent ink and --positive are both #036B4E, so a two-series chart drew both series in ONE colour. Measured on the deployed site: two lines, one unique stroke.
  • A categorical series is not a state. Series 2 does not mean "good", it means "the second thing". Borrowing the semantic palette fuses two vocabularies, so a reader who has learned that red is a failure meets a red that means "Solar".

So a chart's colours are the same in all three brands, for the same reason the map's scale is. Every hue clears 3:1 against both surfaces in its theme — the floor for a graphical object that carries meaning, and the reason the light and dark sets are different values rather than the same ones.

If a series genuinely IS a state — covered vs gap — use the band scale and say so, rather than hoping series 2 lands on green.

Five series is the cap, and it is a hard one (SERIES_MAX). The eye cannot hold six categorical colours and the palette has no sixth value to give. A sixth series is a chart that should be a table.

Rules

  • Axis labels and every figure are font-mono + tabular-nums. Series names are .mono-caps.
  • A legend only when there is more than one series to name. One series with a legend is a label pretending to be a key.
  • area is for ONE series. Two filled areas fight, and the one behind loses.
  • A reference line is a target the reader is measuring against — not a mean, not a decoration.
  • No shadow, no gradient fill, no 3D. The surface rules apply inside a chart.
  • Every component takes its data as a prop and computes nothing about the domain: what a number MEANS is the caller's.
  • muted on a ranking row recedes it without recolouring it — for rows outside the window in force. Colour is a state, never a rank: a row does not turn red for scoring badly.

When not to use one

A single figure is a Metric, not a chart. Twelve points in a line of text is a Sparkline — hand-drawn SVG, no library. Recharts earns its place where the axes, the ticks and the tooltip are the actual work.