Data visualisation
One palette, four renderers, and one standard for how a chart is built. @pepperui/charts 1.1.5 holds both; ECharts and Chart.js read them in the browser, the PPTX exporter reads the same values in Python, and the Figma chart recipes cite them. No colour and no geometry is written in the package’s source — npm test fails on one, and reads every value back out of tokens.css.
Every chart on this page is drawn from those numbers, part by part, in the same HTML and CSS the slide previews use. What you see here is what a chart in a deck, a dashboard or a Figma frame is supposed to look like.
How a chart is built
Section titled “How a chart is built”Twelve rules. They were settled on rendered pairs — the same chart drawn both ways, side by side — rather than described, and they live in one file so no renderer can hold its own copy. Eleven of them are about a chart’s shape; the twelfth is the one place colour is a rule rather than a palette.
The baseline is chart/rest at 2 px, heavier than the 1 px grid, and it belongs to the category axis. The value axis draws no line of its own.
The grid keeps a horizontal line at every tick, behind the bars — the values can be read off the plot as well as off the labels.
4 px on the top corners only, and never wider than 96. A column rounded all round reads as a floating pill.
The joints stay square: a rounded joint draws a gap between two values that is not in the data.
A chart with exactly TWO series is one thing measured against the rest of it, so the second series is chart/rest — the same grey the two-slice donut uses, not the accent’s second tint. Three series or more take the accent’s own tints as before.
The spline is 4 px and every point carries a 9 px marker. A line with no markers hides where the data actually is.
A ranked list reads top-down from the largest, and the lane for the row names is as wide as the longest name — nothing is reserved in advance.
The band is the series colour at 12 % under the value it belongs to; the series it is compared against runs beneath as a dashed chart/4 line, 3 px, 6 on 6 off, and each line ends in a marker.
The ring stays clean — no text on it, no leader lines out of it. The cutout is 72 % and the segment borders are 3 px in chart/on-fill. The legend lane is measured from its own entries, so the last one is never cut.
Exactly two slices read as share-against-rest: the share keeps the accent’s chart/1 and the remainder is always chart/rest, never chart/2 — two accent hues would read as two categories.
The line and nothing else: no axis, no grid, no labels. It sits inside a card that already says what the number is.
A one-series chart has three treatments
Section titled “A one-series chart has three treatments”All three are correct, and the system carries all three rather than choosing for you. Pick the one the screen needs: one flat colour when the bars are one thing measured over time, the accent’s own tints when the bars are being compared with each other, and multicolor when the chart is set to it by hand.
Every bar in the accent’s chart/1. This is what “a chart follows the accent” means, and it is the default in an accent mode.
chart/1 to chart/5, cycling — for a comparison across the bars.
The mode’s chart/1 to chart/5 — red, yellow, blue, grey, then the second red its palette continues with. Multicolor is set by hand, a deck chooses it and the machine never does, and a chart in it cycles across the bars rather than painting them all red.
The series palettes
Section titled “The series palettes”Five colours per accent mode, in order. Blue and red lead with the accent’s two hues and end in greys; yellow’s second series is grey, because a yellow tint vanishes on the card; multicolor cycles red, yellow, blue, then grey — so a chart never has to invent a colour.
| Mode | Series 1–5 |
|---|---|
data-accent="blue" |
|
data-accent="red" |
|
data-accent="yellow" |
|
multicolor (8) |
Hover a swatch to see the token it comes from. The multicolor mode is the only palette longer than five, and its series are the three accents in turn rather than one accent’s tints.
The two rules that are not geometry
Section titled “The two rules that are not geometry”- The two-slice donut. Drawn above: the share in series 1, the remainder in
chart/rest. A donut that arrives unstyled is restyled to 70 with no border rather than shipping as a default pie. - The narrow-band floor. When every value in a series sits inside a narrow high band — a spread under 5 % of the maximum — the axis floor lifts to just below the band so the variation is visible; an explicit axis minimum always wins.
The type on a chart
Section titled “The type on a chart”| Canvas | Size | Weight |
|---|---|---|
| slide | 15 | 400 |
| web-desktop | 12 | 500 |
The face is Poppins, sans-serif and a strong label is weight 600. Ink, grid, the rest slice and the label inside a fill are token roles, not chart settings.
Where a chart’s colour is open
Section titled “Where a chart’s colour is open”Three of the open contrast questions are here — a data label written in white inside a yellow fill, a yellow two-slice donut whose share and remainder are 1.15 apart, and the dashed forecast line, which reads 1.68 : 1 on its own band. All three are on Accessibility; none of them fails the build.
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.