Charts.
Chart components built on the Data Viz Palette. Anatomy, types, states, annotation patterns, small multiples, and do / don't rules — all in the slate / switch family so a dashboard reads as one fabric.
Anatomy
The canonical chart frame every type extends.Every Swivel chart is built on the same frame: a value axis on the left, a category axis on the bottom, dashed gridlines on major y-ticks, a single-series title and time stamp in the header, and a dark tooltip on hover. Drop a chart in this frame and the rest of the design system aligns to it.
.demo-title · .demo-meta--fs-axis-title (13px UPPERCASE Antarctica) title at the midline. Tick labels right-aligned in --fs-axis-tick (12px Avantt SemiBold).--chart-grid. No vertical gridlines unless the x-axis is also quantitative.--graphite-bg. Label sits flush to the right margin, never floating mid-plot.--viz-slate by default.--fs-axis-tick (12px Avantt SemiBold). Aim for 4-6 labels max; thin or rotate before truncating.A single tooltip pattern works for every chart on this page. Surface plate, hairline stroke, UI/Default for the timestamp and series names, UI/Small for the right-aligned values. The hovered series promotes to Avantt SemiBold; the rest stay muted in --graphite-bg. Catch-all rows like "Other" sit at the bottom in a neutral graphite swatch.
Tooltip rules
- Fill / stroke — always
--surface-basewith a 1px--surface-strokehairline. Never invert the plate per theme — the tokens already adapt. - Title — UI/Default (Antarctica 14px, regular). Full date + time, no abbreviations. Lives at the top, left-aligned, no underline or divider.
- Series rows — name in UI/Default muted (
--graphite-bg), value in UI/Small (Avantt SemiBold 12px) right-aligned with tabular numerals. Swatch is a 16×3 rounded line, not a square — matches the line/area-fill the tooltip describes. - Active row — the series the cursor is on promotes to Avantt SemiBold +
--graphite-90. Only one row at a time. Don't reorder rows on hover; visual stability beats hover novelty. - "Other" row — always last, swatch in
--graphite-20, never in a series color.
Tickmark labels are read in passing — they need to fit in a narrow gutter without truncating, and the unit must be unambiguous at a glance. If the y-axis is a dollar value, every tick carries the currency symbol, even when the axis title already says "revenue." Abbreviate magnitudes so labels never wrap: thousands as K, millions as MM, billions as B. Apply the same rule to tooltip values, KPI cards, and bar end-labels so the formatting is consistent everywhere a number appears.
$16K
$8MM
$16,000 → $16K; 8,000,000 → $8MM. The currency symbol is on every tick, not just the topmost — readers scan ticks in any order.Axis label rules
- Typography is tokenized — tick + category labels use
--fs-axis-tick(12px Avantt SemiBold), rotated value-axis titles use--fs-axis-title(13px Antarctica Medium, UPPERCASE, 4% tracking). Don't hand-set sizes in chart code; the aliases keep every chart at the same density and theme-swap cleanly. - Currency on every tick — if the metric is money, every label carries
$(or€/£/ etc.). Including the symbol on the axis title alone isn't enough; readers don't scan top-down. - Abbreviate by magnitude —
1,000→1K,1,000,000→1MM,1,000,000,000→1B. UseMM(notM) for millions in finance contexts to avoid confusion with thousands in roman-numeral notation; switch toMonly if the surrounding product uses it consistently. - Pick one suffix per axis — don't mix
$500,$1.5K,$2Kon the same scale. Snap the whole axis to the largest tick's unit so labels line up in length. - Precision follows the range — 0–10MM gets one decimal (
$2.5MM); 0–100MM rounds to whole units ($25MM). Never write more decimals than the data resolves. - Non-currency metrics still abbreviate —
1.2K impressions,8MM bids. Just drop the$. Percentages keep%on every tick by the same rule. - Negative values — currency symbol goes inside the sign:
−$2.4K, never$−2.4K. Divergent bars and waterfall charts both rely on this. - Tooltips show full precision — the axis abbreviates for scanning; the tooltip is where exact figures live (
$16,482.30). Same goes for bar end-labels when the chart is wide enough.
Line
Continuous metric over time. The default chart for ratios and rates.Use line for continuous metrics over time — fill rate, CPM, bid density, ROI. One series uses --viz-slate. Add up to five comparators using the categorical palette in order. Above six, switch to small multiples (§11) instead of stacking lines.
Rules
- Order series by importance, not alphabetically. Primary metric →
--viz-slate, comparator →--viz-switch, then deep, steel, mist, graphite. - Connect through missing data with a dashed segment. Don't drop to zero on null.
- No markers on lines < 200px wide — they crowd the path. Use markers on small multiples and sparklines instead.
Area
Magnitude over time. Use when total matters more than rate-of-change.Single-series area is a line with a 10-15% fill underneath, anchored to the zero baseline. Stacked area for part-of-whole over time. Keep the palette to the slate/switch family — never mix in semantic colors (those mean "good/bad," not "category").
Bar
Categorical comparison. Sortable, rankable, and almost always the right answer.Bars beat pies, donuts, and most "creative" charts at the comparison job. Four variants cover 90% of cases: vertical for time, horizontal for ranked categories, grouped for split comparisons, stacked for part-of-whole. Always sort by value unless time order is the point.
KPI card
The most-used pattern on the Command surface.A KPI card pairs a single value with a directional delta. The number is the answer; the delta is the trend. No axes, no chart — if you need history, promote to a real chart. Stick to --viz-slate and let the delta color carry good/bad.
KPI card rules
- One number, one label, one delta. If you need a second dimension, the answer is a chart, not a bigger card.
- Don't bury the delta. Arrow + value next to the metric. Color from
--success/--error/--slate-100. - The label says what window the delta covers ("vs. last 7d"), not the card chrome.
Donut
One number with one breakdown. Sparingly.Use donuts only when there's a single dominant fact you want to anchor in the center (a percent, a count) and at most three or four slices supporting it. Past four slices, switch to a horizontal bar — humans can rank lengths but not arc lengths. Never use a pie chart with no center; the donut's center is what justifies the format.
- Five or more slices → horizontal bar
- Slice values within 5% of each other → bar
- No anchor number for the center → bar
- You need trend, not snapshot → line
Heatmap
Two categorical dimensions, one magnitude. Uses sequential ramps.A grid of cells colored by a sequential ramp from the palette. Heatmaps reward dense data — give them enough rows and columns to show pattern, not so many cells become noise. Pair with a one-line color legend below.
Scatter
Two continuous dimensions. Optional third encoded as size.Use scatter when the question is "are these correlated" or "where are the outliers." Plot points at 4-5px radius, 60% opacity so density reads as darker clusters. For a categorical third dimension, color by the categorical palette in order. For a continuous third, encode as area (not radius — area is what eyes compare).
Bullet
Actual vs. target with a qualitative range. Replaces gauges.A bullet chart fits a gauge's job in a tenth of the space. A solid bar shows actual, a vertical tick shows target, and a banded background shows poor/ok/good ranges. Use any time someone asks for a gauge or speedometer.
States
Loading, empty, no-data, partial, and error.Every chart has five non-happy states. Treat them as first-class components, not afterthoughts. A skeleton tells the user data is on the way; an empty state tells them the query is valid but turned up nothing; a no-data slice tells them part of the range is unknown; an error state tells them the fetch failed and offers a retry.
Annotations
Target lines, event markers, range bands, and callouts.Annotations are how a chart says something. They earn their place — every annotation should answer a question the chart's bare shape doesn't. Four canonical kinds: target line, event marker, range band, point callout.
Small multiples
When you'd otherwise stack six lines on one chart.A grid of tiny charts on a shared scale. Reach for these the moment a multi-series line gets crowded — they always win the comparison job past three series. Use the same y-scale across every tile so heights compare directly, and never use more than one series color per tile.
Do / Don't
The five biggest ways charts go off-brand.Most chart problems come from the same handful of mistakes. Each pair below shows the wrong choice and the right one.
--viz-slate, comparator in --viz-switch, then deep → steel → mist → graphite. Past six series, switch to small multiples.- Line — continuous metric over time. Default for fill rate, CPM, ROI.
- Area — magnitude over time. Total matters more than rate-of-change.
- Bar (vertical) — value over time when the gap between points matters.
- Bar (horizontal) — ranked categories. Default for "top N."
- Stacked bar / area — part-of-whole when the total is also interesting.
- Divergent bar — plus/minus vs. a baseline. Use diverging palette.
- Sparkline — context for a single metric. Inline only — don't combine with axes.
- Donut — one anchor number with ≤4 supporting slices.
- Heatmap — two categorical dimensions, one magnitude. Sequential palette.
- Scatter — correlation, outliers. Two continuous dimensions.
- Bullet — actual vs. target with qualitative bands. Use instead of a gauge.
- Small multiples — past three series, always.