The shell every chart shares: series mapped to colour tokens, locale-aware formatting, an interactive legend, loading / refreshing / empty / error states, a generated text summary and a data-table alternative. Ready charts sit on top of it; raw Recharts works inside it too.
Oct 1 – Oct 30. Visits: low 1,180 (Oct 1), high 1,855 (Oct 26), average 1,500.93. Full reads: low 661 (Oct 1), high 1,065 (Oct 26), average 848.47.
| Date | Visits | Full reads |
|---|---|---|
| Oct 1, 2026 | 1,180 | 661 |
| Oct 2, 2026 | 1,300 | 760 |
| Oct 3, 2026 | 1,412 | 785 |
| Oct 4, 2026 | 1,417 | 804 |
| Oct 5, 2026 | 1,499 | 812 |
| Oct 6, 2026 | 1,560 | 878 |
| Oct 7, 2026 | 1,504 | 862 |
| Oct 8, 2026 | 1,523 | 835 |
| Oct 9, 2026 | 1,431 | 799 |
| Oct 10, 2026 | 1,422 | 826 |
| Oct 11, 2026 | 1,407 | 781 |
| Oct 12, 2026 | 1,300 | 736 |
| Oct 13, 2026 | 1,296 | 696 |
| Oct 14, 2026 | 1,212 | 734 |
| Oct 15, 2026 | 1,241 | 713 |
| Oct 16, 2026 | 1,292 | 704 |
| Oct 17, 2026 | 1,269 | 706 |
| Oct 18, 2026 | 1,360 | 790 |
| Oct 19, 2026 | 1,373 | 812 |
| Oct 20, 2026 | 1,490 | 840 |
| Oct 21, 2026 | 1,610 | 870 |
| Oct 22, 2026 | 1,632 | 967 |
| Oct 23, 2026 | 1,739 | 989 |
| Oct 24, 2026 | 1,829 | 1,003 |
| Oct 25, 2026 | 1,806 | 1,005 |
| Oct 26, 2026 | 1,855 | 1,065 |
| Oct 27, 2026 | 1,789 | 1,043 |
| Oct 28, 2026 | 1,799 | 1,011 |
| Oct 29, 2026 | 1,794 | 971 |
| Oct 30, 2026 | 1,687 | 996 |
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { AreaChart, type ChartConfig } from "@vamos-ui/react/charts";
const config = {
visits: { label: "Visits" },
revenue: { label: "Revenue", format: "currency", color: "chart-2" },
} satisfies ChartConfig;
<AreaChart title="Traffic" data={rows} x="date" config={config} height="md" />Recharts loads only through @vamos-ui/react/charts — pages without charts never ship it.
Tooltips are opaque (--chart-tooltip) and never blur, even in glass mode: they re-render on every pointer move.
Strokes and text never use the raw accent (lime fails contrast on white); chart-1 is accent-ink.
Examples
Chart card with range (CRM)
Card header + 7D / 30D / 90D switch. The chart's title stays the accessible name; the visible title lives in the card.
CRM · Sales
Pipeline value
Open and closed-won deals, daily
Oct 11 – Nov 9. Open pipeline: low $563,610.00 (Oct 11), high $655,702.00 (Oct 24), average $627,344.30. Closed won: low $186,379.00 (Oct 11), high $248,256.00 (Oct 29), average $229,276.67.
| Date | Open pipeline | Closed won |
|---|---|---|
| Oct 11, 2026 | $563,610.00 | $186,379.00 |
| Oct 12, 2026 | $573,287.00 | $189,919.00 |
| Oct 13, 2026 | $583,507.00 | $193,887.00 |
| Oct 14, 2026 | $593,978.00 | $198,214.00 |
| Oct 15, 2026 | $604,397.00 | $202,817.00 |
| Oct 16, 2026 | $614,466.00 | $207,608.00 |
| Oct 17, 2026 | $623,899.00 | $212,493.00 |
| Oct 18, 2026 | $632,434.00 | $217,375.00 |
| Oct 19, 2026 | $639,848.00 | $222,159.00 |
| Oct 20, 2026 | $645,960.00 | $226,749.00 |
| Oct 21, 2026 | $650,643.00 | $231,059.00 |
| Oct 22, 2026 | $653,825.00 | $235,006.00 |
| Oct 23, 2026 | $655,495.00 | $238,521.00 |
| Oct 24, 2026 | $655,702.00 | $241,545.00 |
| Oct 25, 2026 | $654,554.00 | $244,032.00 |
| Oct 26, 2026 | $652,211.00 | $245,954.00 |
| Oct 27, 2026 | $648,883.00 | $247,294.00 |
| Oct 28, 2026 | $644,818.00 | $248,056.00 |
| Oct 29, 2026 | $640,295.00 | $248,256.00 |
| Oct 30, 2026 | $635,608.00 | $247,929.00 |
| Oct 31, 2026 | $631,060.00 | $247,120.00 |
| Nov 1, 2026 | $626,948.00 | $245,893.00 |
| Nov 2, 2026 | $623,552.00 | $244,320.00 |
| Nov 3, 2026 | $621,123.00 | $242,483.00 |
| Nov 4, 2026 | $619,872.00 | $240,471.00 |
| Nov 5, 2026 | $619,967.00 | $238,381.00 |
| Nov 6, 2026 | $621,518.00 | $236,307.00 |
| Nov 7, 2026 | $624,579.00 | $234,347.00 |
| Nov 8, 2026 | $629,144.00 | $232,593.00 |
| Nov 9, 2026 | $635,146.00 | $231,133.00 |
Colour tokens
Series reference tokens (chart-1…6, accent-ink, success…), never hex — each scope re-colours itself across accents and materials.
lime · solid
W40 – W45. Sign-ups: low 182 (W40), high 298 (W45), average 232.67. Trials: low 96 (W40), high 177 (W45), average 139.
| Week | Sign-ups | Trials |
|---|---|---|
| W40 | 182 | 96 |
| W41 | 214 | 120 |
| W42 | 198 | 131 |
| W43 | 263 | 148 |
| W44 | 241 | 162 |
| W45 | 298 | 177 |
ocean · glass
W40 – W45. Sign-ups: low 182 (W40), high 298 (W45), average 232.67. Trials: low 96 (W40), high 177 (W45), average 139.
| Week | Sign-ups | Trials |
|---|---|---|
| W40 | 182 | 96 |
| W41 | 214 | 120 |
| W42 | 198 | 131 |
| W43 | 263 | 148 |
| W44 | 241 | 162 |
| W45 | 298 | 177 |
ember · solid
W40 – W45. Sign-ups: low 182 (W40), high 298 (W45), average 232.67. Trials: low 96 (W40), high 177 (W45), average 139.
| Week | Sign-ups | Trials |
|---|---|---|
| W40 | 182 | 96 |
| W41 | 214 | 120 |
| W42 | 198 | 131 |
| W43 | 263 | 148 |
| W44 | 241 | 162 |
| W45 | 298 | 177 |
rose · glass
W40 – W45. Sign-ups: low 182 (W40), high 298 (W45), average 232.67. Trials: low 96 (W40), high 177 (W45), average 139.
| Week | Sign-ups | Trials |
|---|---|---|
| W40 | 182 | 96 |
| W41 | 214 | 120 |
| W42 | 198 | 131 |
| W43 | 263 | 148 |
| W44 | 241 | 162 |
| W45 | 298 | 177 |
graphite · solid
W40 – W45. Sign-ups: low 182 (W40), high 298 (W45), average 232.67. Trials: low 96 (W40), high 177 (W45), average 139.
| Week | Sign-ups | Trials |
|---|---|---|
| W40 | 182 | 96 |
| W41 | 214 | 120 |
| W42 | 198 | 131 |
| W43 | 263 | 148 |
| W44 | 241 | 162 |
| W45 | 298 | 177 |
Formatters, en-US vs tr-TR
One FormatSpec per series. Axis ticks are compact, tooltip and table use the full form, all from the LocaleProvider.
en-US
Jun – Oct. Revenue: low $1,092,300.00 (Aug), high $1,712,400.00 (Oct), average $1,372,820.00.
| Month | Revenue |
|---|---|
| Jun | $1,184,000.00 |
| Jul | $1,326,500.00 |
| Aug | $1,092,300.00 |
| Sep | $1,548,900.00 |
| Oct | $1,712,400.00 |
tr-TR
Haz – Eki. Revenue: low ₺1.092.300,00 (Ağu), high ₺1.712.400,00 (Eki), average ₺1.372.820,00.
| Month | Revenue |
|---|---|
| Haz | ₺1.184.000,00 |
| Tem | ₺1.326.500,00 |
| Ağu | ₺1.092.300,00 |
| Eyl | ₺1.548.900,00 |
| Eki | ₺1.712.400,00 |
States
Chart-shaped skeletons, a dimmed refresh, an empty state that keeps its height and an error with retry.
loading — chart-shaped, no spinner
W41 – W44. Tickets: low 128 (W42), high 167 (W43), average 147.
refreshing — old data dimmed, thin bar
W41 – W44. Tickets: low 128 (W42), high 167 (W43), average 147.
| Week | Tickets |
|---|---|
| W41 | 142 |
| W42 | 128 |
| W43 | 167 |
| W44 | 151 |
empty — keeps its height
No tickets in the last 7 days
error — retry
The reporting service timed out.
View as table
The data table is always present for screen readers; tableToggle shows it to everyone.
May – Oct. Starter: low 4.6% (Oct), high 6.4% (Jul), average 5%. Team: low 2.4% (Oct), high 3.4% (May), average 3%. Business: low 0.8% (Oct), high 1.4% (Jun), average 1%.
| Month | Starter | Team | Business |
|---|---|---|---|
| May | 6.1% | 3.4% | 1.2% |
| Jun | 5.8% | 3.1% | 1.4% |
| Jul | 6.4% | 2.9% | 1.1% |
| Aug | 5.2% | 2.7% | 0.9% |
| Sep | 4.9% | 2.6% | 1% |
| Oct | 4.6% | 2.4% | 0.8% |
Controlled legend
Legend items are toggle buttons (aria-pressed). The last visible series cannot be hidden.
Engineering – Finance. Annual leave: low 37 (Finance), high 142 (Engineering), average 83.4. Sick leave: low 9 (Finance), high 41 (Support), average 24.4.
| Team | Annual leave | Sick leave | Parental leave |
|---|---|---|---|
| Engineering | 142 | 38 | 60 |
| Sales | 96 | 22 | 14 |
| Support | 88 | 41 | 20 |
| Marketing | 54 | 12 | 30 |
| Finance | 37 | 9 | 0 |
hidden: parental
Drill-down (CMS)
onPointClick on a bar, or on a row header in the table view — the keyboard path.
Product news – Engineering. Posts: low 9 (Case studies), high 31 (Guides), average 18.
| Category | Posts |
|---|---|
| Product news | 18 |
| Guides | 31 |
| Case studies | 9 |
| Engineering | 14 |
Click a bar (or a row in the table view) to list its posts.
Raw Recharts
Any Recharts tree inside <Chart> + <ChartFrame>; use ChartXAxis, ChartYAxis, ChartTooltip and seriesColor(key).
00:00 – 20:00. p95: low 241 ms (04:00), high 418 ms (12:00), average 333.5 ms. p50: low 98 ms (04:00), high 168 ms (12:00), average 132.83 ms.
| Hour | p95 | p50 |
|---|---|---|
| 00:00 | 284 ms | 112 ms |
| 04:00 | 241 ms | 98 ms |
| 08:00 | 362 ms | 141 ms |
| 12:00 | 418 ms | 168 ms |
| 16:00 | 391 ms | 152 ms |
| 20:00 | 305 ms | 126 ms |
API
Chart (shared by every ready chart)
| Prop | Type | Default |
|---|---|---|
titleRequired. Accessible name of the figure and caption of the data table (not shown visually). | string | — |
dataRows. Dates as "YYYY-MM-DD" strings, money as numbers or decimal strings. | T[] | — |
configSeries key → { label, color?, format?, axis?, pattern?, icon?, hidden? }. Key order = legend and colour order. | ChartConfig | — |
xCategory / time key. | keyof T | — |
xFormatx format. Default: "YYYY-MM-DD" → "Nov 1", everything else as is. | FormatSpec | — |
yFormatValue axis format. Default: the first series' format, compact. | FormatSpec | — |
xLabelHeader of the x column in the data table. | string | — |
height160 / 260 / 360 px or pixels. Reserved before the chart measures (no layout shift). | "sm" | "md" | "lg" | number | "md" |
aspectWidth / height ratio instead of a height. | number | — |
state{ status: "loading" | "refreshing" | "empty" (message, action) | "error" (message, onRetry) | "ready" }. Default: empty when data is empty. | ChartState | — |
summaryText alternative (aria-describedby). Default: generated range, low, high and average per series. | string | (data) => string | — |
tableToggleShows the "View as table" switch. | boolean | false |
legendLegend position. Items toggle series. | "top" | "bottom" | "none" | "top" with 2+ series |
hiddenSeries / defaultHiddenSeries / onHiddenSeriesChangeControlled or uncontrolled hidden series. | string[] | — |
tooltipIndicatorSwatch in tooltip rows. | "dot" | "line" | "dashed" | "dot" |
animateTransitions on data change; always off under prefers-reduced-motion. | boolean | true |
onPointClickDrill-down. Also turns the table's row headers into buttons. | (row, seriesKey) => void | — |
toolbarExtra controls at the end of the legend row. | ReactNode | — |
labelsBuilt-in strings (chart namespace): viewTable, empty, error, retry, total, other… | Partial<ChartLabels> | — |
SeriesConfig
| Prop | Type | Default |
|---|---|---|
labelLegend, tooltip, table header and summary text. | string | — |
color"chart-1"…"chart-6" | "accent" | "accent-ink" | "success" | "warning" | "danger" | "info" | "fg-subtle" | "fg-muted". Exposed as --series-<key>. | ChartColor | chart-1…6 in order |
format"number" | "integer" | "compact" | "percent" (ratio) | "currency" | "duration" | "bytes" | { currency, compact? } | { date } | { relative: true } | (v, locale) => string. | FormatSpec | "number" |
axisValue axis side (Combo). Logical — swaps in RTL. | "start" | "end" | — |
patternStroke pattern. Auto-assigned with more than 3 series. | "solid" | "dashed" | "dotted" | — |
iconIcon in place of the legend swatch. | ComponentType | — |
hiddenStart hidden. | boolean | — |
Raw-mode parts
| Prop | Type | Default |
|---|---|---|
ChartFrameSizes one Recharts chart to the Chart body. | component | — |
ChartTooltipTooltip with the themed, opaque content (indicator, showTotal, showShare, hideLabel). | component | — |
ChartXAxis / ChartYAxisAxes with token ticks, formatters, measured y width (format, keys, stacked). | component | — |
ChartGrid / ChartReferenceLineGrid in --chart-grid; dashed reference line with label and colour token. | component | — |
useChart()config, series, visibleSeries, isHidden, toggleSeries, formatSeries, formatTick, formatX, f, t. | hook | — |
resolveChartColor / seriesColor / seriesPalette"chart-2" → "var(--chart-2)"; key → "var(--series-key)"; first n palette tokens. | function | — |