Tollerud

Tollerud UI/Charts / TimeSeriesChart

Charts

Charts

Palette-aware SVG charts — no Recharts dependency. Yellow marks the highlight series; grids and axes use --chart-grid and --chart-axis tokens.

Overview

All chart components ship from @tollerud/ui. They inherit Tollerud tokens from globals.css — no extra charting library install.

code
import {
  TimeSeriesChart,
  TIME_SERIES_PRESETS,
  BarChart,
  AreaChart,
  Donut,
  SegmentBarChart,
  Sparkline,
  Gauge,
} from '@tollerud/ui'
ComponentUse when
TimeSeriesChartWide price/metric history — stepped/linear curves, hover + keyboard crosshair, range selector, one or many series
SparklineInline trends in tables, stat rows, or cards — optional interactive tooltip
AreaChartSimple trend — static by default, or interactive with tooltip + keyboard nav
BarChartCategory comparison — static, or interactive focusable bars with tooltips
DonutPart-to-whole breakdown — palette-cycled legend, optionally interactive
SegmentBarChartHorizontal stacked proportion bar — category spend/budget splits with in-bar % labels
GaugeSingle metric as a radial dial — disk %, load, quota; tone thresholds
HeatmapActivity over time — calendar/contributions grid with intensity buckets
InteractionApplies to
interactive — crosshair/tooltip + keyboard (Tab, ←/→, Home/End, Esc), SR announcementsAreaChart, Sparkline, BarChart, Donut, SegmentBarChart (opt-in); TimeSeriesChart (always)
srTable — visually-hidden data table for screen readersTimeSeriesChart (default on), AreaChart (default = interactive)
formatValue / ariaLabel — value formatting + accessible nameall interactive charts
CHART_SERIES_COLORS — the --chart-1…5 palette cycleDonut segments & TimeSeriesChart series without an explicit color
SEGMENT_BAR_COLORS — yellow-on-noir intensity scaleSegmentBarChart segments without an explicit color

Interactive wide SVG chart for dates + values. Fully keyboard accessible (≥ 4.8.42): Tab focuses the chart and activates the latest point, ←/→ step through points with the crosshair and tooltip following, Home/End jump to the ends, Esc clears — and screen readers hear each keyboard-selected point. A visually-hidden data table (srTable, on by default; ≥ 4.8.45) exposes every point to screen readers. Pass series instead of data for multiple lines (≥ 4.8.46) — shared crosshair, stacked tooltip, palette-cycled colors. Use curve="step" for prices held between samples. Pass ranges with TIME_SERIES_PRESETS or custom durationMs filters, or filter data yourself and omit ranges.

PropsTimeSeriesChartProps
PropType
data?TimeSeriesPoint[]
* Multiple index-aligned series (same dates by position). Takes precedence
* over `data`. Each series gets a line + crosshair dot; the tooltip and SR
* table stack all series at the active point. Area fill and the latest-value
* badge are single-series only.
*/
series?TimeSeriesSeries[]
height?number
curve?'linear' | 'step'
yAxis?'left' | 'right' | 'none'
padding?Partial<ChartPadding>
formatValue?(value: number) => string
valuePrefix?string
valueSuffix?string
formatDate?(date: Date) => string
formatAxisDate?(date: Date) => string
showLatestValue?boolean
ranges?TimeSeriesRange[]
range?string
onRangeChange?(value: string) => void
toolbarLeft?ReactNode
renderTooltip?(point: TimeSeriesPoint, index: number, formattedValue: string) => ReactNode
showLegend?boolean
emptyMessage?string
locale?string
ariaLabel?string
srTable?boolean
Price history · demo
16,33816,63216,92617,220Sep 22Oct 6Oct 20Nov 3Nov 17Dec 1Dec 15
16,599
Time series chart
DateValue
Sep 22, 202617,159
Sep 29, 202617,064
Oct 6, 202616,921
Oct 13, 202616,721
Oct 20, 202616,595
Oct 27, 202616,399
Nov 3, 202616,546
Nov 10, 202616,553
Nov 17, 202616,700
Nov 24, 202616,747
Dec 1, 202616,564
Dec 8, 202616,730
Dec 15, 202616,599

Basic

13,76413,93814,11214,286Mar 23Apr 6Apr 13
13,800
Time series chart
DateValue
Mar 23, 202613,999
Apr 6, 202614,250
Apr 13, 202613,800
time-series-basic

Controlled range

Pair range with onRangeChange when the parent owns filter state — e.g. alongside a store selector in toolbarLeft.

Price history
16,33816,63216,92617,220Sep 22Oct 6Oct 20Nov 3Nov 17Dec 1Dec 15
16,599
Time series chart
DateValue
Sep 22, 202617,159
Sep 29, 202617,064
Oct 6, 202616,921
Oct 13, 202616,721
Oct 20, 202616,595
Oct 27, 202616,399
Nov 3, 202616,546
Nov 10, 202616,553
Nov 17, 202616,700
Nov 24, 202616,747
Dec 1, 202616,564
Dec 8, 202616,730
Dec 15, 202616,599
time-series-controlled

Custom ranges (Norwegian)

TIME_SERIES_PRESETS ships English labels. For Norwegian UI, pass your own ranges and set locale="nb-NO" for axis/tooltip formatting.

Prishistorikk
16 338 ,-16 632 ,-16 926 ,-17 220 ,-22. sep.6. okt.20. okt.3. nov.17. nov.1. des.15. des.
16 599 ,-
Time series chart
DateValue
22. sep. 202617 159 ,-
29. sep. 202617 064 ,-
6. okt. 202616 921 ,-
13. okt. 202616 721 ,-
20. okt. 202616 595 ,-
27. okt. 202616 399 ,-
3. nov. 202616 546 ,-
10. nov. 202616 553 ,-
17. nov. 202616 700 ,-
24. nov. 202616 747 ,-
1. des. 202616 564 ,-
8. des. 202616 730 ,-
15. des. 202616 599 ,-
time-series-ranges

valuePrefix / valueSuffix

Quick affixes for tooltip, Y-axis, and latest-value badge — without a custom formatValue. Ignored when formatValue is set. For decimal unit rates, prefer formatChartDecimal via formatValue.

56 $/gal57 $/gal58 $/gal58 $/galMar 23Apr 6Apr 13
56 $/gal
Time series chart
DateValue
Mar 23, 202658 $/gal
Apr 6, 202657 $/gal
Apr 13, 202656 $/gal
time-series-value-affix

formatValue

formatValue formats Y-axis ticks, the latest-value badge, and the default tooltip. It is independent of locale (dates only). Use formatChartDecimal for unit rates like $/gal.

56.3 $/gal57.0 $/gal57.6 $/gal58.3 $/galMar 23Apr 6Apr 13
56.4 $/gal
Time series chart
DateValue
Mar 23, 202658.2 $/gal
Apr 6, 202657.0 $/gal
Apr 13, 202656.4 $/gal
time-series-format-value

Custom tooltip

13,76413,93814,11214,286Mar 23Apr 6Apr 13
13,800
Time series chart
DateValue
Mar 23, 202613,999
Apr 6, 202614,250
Apr 13, 202613,800
time-series-tooltip

Multiple series — shared crosshair, stacked tooltip

DieselPetrolElectric
7,057 kr9,632 kr12,208 kr14,783 krMar 23Apr 6Apr 13
Fuel prices by type
DateDieselPetrolElectric
Mar 23, 202613,999 kr11,479 kr7,699 kr
Apr 6, 202614,250 kr11,685 kr7,838 kr
Apr 13, 202613,800 kr11,316 kr7,590 kr
time-series-multi
TypeShape
TimeSeriesPoint{ date, value, label?, meta? }date accepts Date, ISO string, or timestamp
TimeSeriesSeries{ label, points, color? } — pass an array as series for multi-line charts (≥ 4.8.46); omit color to cycle --chart-1…5
TimeSeriesRange{ value, label, durationMs?, disabled? } — omit durationMs for all time
TIME_SERIES_PRESETSEnglish defaults: 3 mo · 6 mo · 1 yr · 2 yr · All

Compact inline SVG trend. Add curve="step", fill, and interactive for price-style micro charts — common in DataTable cells. Interactive sparklines (≥ 4.8.43) get a tooltip and keyboard navigation (Tab, ←/→, Home/End, Esc) with screen-reader announcements; pass formatValue and ariaLabel for meaningful output. The SVG is clipped to its viewBox so stroke bleed at small sizes (e.g. 84×26) is prevented.

PropsSparklineProps
PropType
datanumber[]
width?number
height?number
w?number
h?number
color?string
curve?'linear' | 'step'
fill?boolean
* Fill the container width instead of a fixed `width` (measured with a
* ResizeObserver, plotted in pixels so dots stay round). `height` still
* applies. Off by default — Sparkline stays a fixed micro-chart for table
* cells.
*/
fluid?boolean
interactive?boolean
formatValue?(value: number) => string
ariaLabel?string
Network in
Price trend
Errors

Linear

sparkline-linear

Stepped with fill and hover

sparkline-step

Small size — step+fill at 84×26 (list row usage)

sparkline-step-small

Fluid — fills its container (≥ 4.8.48)

sparkline-fluid

Area/line chart for simple dashboards. Static and decorative by default; add interactive (≥ 4.8.43) for a crosshair, tooltip, and full keyboard navigation (Tab, ←/→, Home/End, Esc) with screen-reader announcements plus a visually-hidden data table (srTable; ≥ 4.8.45). Pass labeled points ({ value, label }) so tooltips, announcements, and the table name each point; plain number arrays keep working. Fluid width with round markers at any size (≥ 4.8.47 — plotted in real pixels, not a stretched viewBox). Use TimeSeriesChart when you need dates, ranges, or axes.

PropsAreaChartProps
PropType
datanumber[] | AreaChartPoint[]
height?number
* Hover/keyboard interactivitycrosshair, tooltip, arrow-key navigation,
* and screen-reader announcements. Off by default — the static chart stays
* a decorative `aria-hidden` graphic.
*/
interactive?boolean
formatValue?(value: number) => string
renderTooltip?(point: AreaChartPoint, index: number, formattedValue: string) => ReactNode
ariaLabel?string
srTable?boolean

CPU load · 24h

area-chart

Interactive — labeled points, keyboard accessible

Requests per hour

Requests per hour
PointValue
09:00420 req
10:00560 req
11:00610 req
12:00540 req
13:00720 req
14:00680 req
area-chart-interactive

Vertical bars with optional yellow accent on one series. Values render above each bar; pass formatValue to format them. Add interactive (≥ 4.8.44) for focusable bars: Tab reaches the chart, ←/→ move between bars, Home/End jump, Esc dismisses — each bar announces its label and value to screen readers, and hover or focus shows a tooltip. Bar-height transitions respect prefers-reduced-motion. For multiple series (≥ 4.8.49), pass series + categories for grouped bars, or add stacked for stacked bars — palette-cycled with a legend.

PropsBarChartProps
PropType
data?BarChartDatum[]
series?BarChartSeries[]
categories?string[]
stacked?boolean
height?number
* Focusable bars/columns with tooltipsTab reaches the chart, ←/→ move
* between targets (roving tabindex), Home/End jump, Esc dismisses. Each
* carries an aria-label announced on focus.
*/
interactive?boolean
formatValue?(value: number) => string
showLegend?boolean
ariaLabel?string

Requests / weekday

32
48
41
67
55
22
18
Mon
Tue
Wed
Thu
Fri
Sat
Sun
bar-chart

Interactive — focusable bars with tooltips

Sales by city

Oslo
Bergen
Tromsø
bar-chart-interactive

Grouped series (≥ 4.8.49)

Resource use by host

CPUMemory
emma
pia
iris
bar-chart-grouped

Stacked series (≥ 4.8.49)

Spend by category

ComputeStorageNetwork
Q1
Q2
Q3
Q4
bar-chart-stacked

Donut chart with segment legend and percentages. Segment colors are optional (≥ 4.8.44) — omitted colors cycle the --chart-1…5 palette (also exported as CHART_SERIES_COLORS). Add interactive for a focusable legend: Tab reaches it, ↑/↓ move between rows, hover or focus highlights the arc, dims the others, and reveals the raw value — each row announces label, value, and share to screen readers. Add fluid (≥ 4.8.48) to scale the ring down to fit narrow containers (capped at size, stays circular; legend wraps below).

PropsDonutProps
PropType
segmentsDonutSegment[]
size?number
* Focusable legend rows that highlight their arcTab reaches the legend,
* ↑/↓ (or ←/→) move between rows, Home/End jump, Esc dismisses. Rows carry
* aria-labels ("Diesel420, 38%") announced on focus; the active row shows
* its value next to the percentage and dims the other arcs.
*/
interactive?boolean
ariaLabel?string
* Scale the ring down to fit narrow containers instead of a fixed `size`
* (capped at `size`, stays perfectly circular — a square viewBox scales
* uniformly). The legend wraps below the ring when space is tight.
*/
fluid?boolean

Storage by host

  • emma45%
  • pia25%
  • iris18%
  • free12%
donut-chart

Palette defaults + interactive legend

Fuel mix

  • Diesel38%
  • Bensin34%
  • El18%
  • Hybrid11%
donut-chart-interactive

Radial dial for a single metric — disk %, load, quota (≥ 4.8.50). A 270° arc fills from bottom-left clockwise. Set tone (default/success/warning/error, token-backed like Meter) to signal thresholds, min/max for a custom range, and formatValue for the centered number. Exposes role=meter with the aria value range; the arc animation respects prefers-reduced-motion. Add fluid to scale it to the container. Complements the linear Meter.

PropsGaugeProps
PropType
valuenumber
min?number
max?number
label?ReactNode
formatValue?(value: number) => string
tone?keyof typeof gaugeTones
size?number
thickness?number
fluid?boolean
ariaLabel?string
41%CPU
72%Disk
94%Memory
gauge

Custom range

2.4Load avg
gauge-range

SegmentBarChart

/charts/segment-bar/

Horizontal stacked proportion bar (≥ 4.15.0) — one rounded bar showing parts of a whole, with in-bar percentage labels and a two-column legend below. Segment colors default to SEGMENT_BAR_COLORS (yellow-on-noir intensity scale). Add interactive for focusable segments with tooltips and keyboard navigation (←/→, Home/End, Esc).

PropsSegmentBarChartProps
PropType
segmentsSegmentBarChartSegment[]
height?number
showPercentLabels?boolean
minPercentLabel?number
formatValue?(value: number) => string
* Focusable segments with tooltipsTab reaches the bar, ←/→ move between
* segments (roving tabindex), Home/End jump, Esc dismisses.
*/
interactive?boolean
ariaLabel?string

Brukt per kategori

  • Mat & drikke6490 kr
  • Drikke3150 kr
  • Leie2400 kr
  • Utstyr890 kr
segment-bar-chart

Interactive segments

Brukt per kategori

  • Mat & drikke6490 kr
  • Drikke3150 kr
  • Leie2400 kr
  • Utstyr890 kr
segment-bar-chart-interactive

Calendar activity heatmap (≥ 4.8.51) — GitHub-contributions style. Pass data of { date, value }; cells are laid out as week columns × weekday rows and bucketed into four intensity levels (a yellow-on-noir scale, overridable via colors). Hover a cell for a date + value tooltip; the grid is aria-hidden with a visually-hidden data table as the screen-reader surface. Set weekStartsOn, startDate/endDate, formatValue/formatDate, and showLegend as needed.

PropsHeatmapProps
PropType
dataHeatmapDatum[]
startDate?Date | string | number
endDate?Date | string | number
weekStartsOn?0 | 1
* Five cell colors by intensityindex 0 = zero/no activity, 1–4 = light→
* strong. Defaults to a yellow-on-noir scale.
*/
colors?[string, string, string, string, string]
formatValue?(value: number) => string
formatDate?(date: Date) => string
locale?string
showLegend?boolean
cellSize?number
cellGap?number
ariaLabel?string
srTable?boolean

Deploy activity · 17 weeks

LessMore
Deploy activity
DateValue
Mar 2, 202611 deploys
Mar 3, 20265 deploys
Mar 5, 202612 deploys
Mar 6, 20266 deploys
Mar 9, 20268 deploys
Mar 10, 20268 deploys
Mar 12, 20263 deploys
Mar 13, 20267 deploys
Mar 14, 20262 deploys
Mar 16, 20267 deploys
Mar 17, 202612 deploys
Mar 18, 20267 deploys
Mar 19, 20263 deploys
Mar 20, 20269 deploys
Mar 23, 20266 deploys
Mar 24, 20264 deploys
Mar 26, 20267 deploys
Mar 27, 20267 deploys
Mar 30, 20264 deploys
Apr 1, 20265 deploys
Apr 2, 20269 deploys
Apr 3, 202612 deploys
Apr 6, 202612 deploys
Apr 7, 202611 deploys
Apr 10, 202611 deploys
Apr 12, 20263 deploys
Apr 14, 202610 deploys
Apr 15, 20269 deploys
Apr 17, 20267 deploys
Apr 20, 20265 deploys
Apr 21, 20269 deploys
Apr 22, 20261 deploys
Apr 23, 20268 deploys
Apr 24, 202611 deploys
Apr 28, 20266 deploys
May 1, 202611 deploys
May 4, 202612 deploys
May 5, 20265 deploys
May 6, 202611 deploys
May 7, 20266 deploys
May 9, 20263 deploys
May 11, 20261 deploys
May 15, 20265 deploys
May 17, 20263 deploys
May 18, 202611 deploys
May 19, 202612 deploys
May 20, 202611 deploys
May 21, 20266 deploys
May 22, 202610 deploys
May 25, 20265 deploys
May 26, 20265 deploys
May 27, 20262 deploys
May 29, 20264 deploys
May 30, 20263 deploys
Jun 1, 20268 deploys
Jun 2, 202610 deploys
Jun 3, 20269 deploys
Jun 4, 20267 deploys
Jun 6, 20262 deploys
Jun 8, 20268 deploys
Jun 9, 20262 deploys
Jun 10, 20265 deploys
Jun 11, 202612 deploys
Jun 12, 20268 deploys
Jun 15, 20267 deploys
Jun 16, 202612 deploys
Jun 17, 20264 deploys
Jun 19, 20261 deploys
Jun 22, 20264 deploys
Jun 23, 20266 deploys
Jun 24, 20263 deploys
Jun 25, 20267 deploys
Jun 26, 20263 deploys
heatmap