Charts
A chart grammar you don't have to outgrow.
TanStack Charts 0.7.2 adds declarative view composition, controlled interactions, motion, spatial layouts, and expanded React Native parity. What changed since 0.6.5.
All mark, no chart.
Make it look like your product.
Same data and scales. CSS variables, themes, mark props, custom tooltips, or your own renderer control the rest.
Editorial
Product
Terminal
Monokai
36.73–42.64 KiB across the controlled suite.
The compact React line is 26.48 KiB gzip; its framework-neutral scene is 10.28 KiB. The comparison methodology and fixtures measure complete cold-page browser bundles, including rendering, axes, styles, and library code.
Cold-page bundle comparison
Controlled 12-case cold-page bundles · minified + gzip
Compose from marks to complete views.
Layer marks when they share a coordinate system. For compound charts, composeViews places complete definitions with fill, grid, layer, and inset utilities. Each view keeps its own scales unless you share or align them. View composition reference.
Weekly activation rate
Jan–May 2026 · illustrative product telemetry
78%
above 70% goal
import { scaleLinear } from '@tanstack/charts-scales/linear'
import { scaleUtc } from 'd3-scale'
import { curveMonotoneX } from 'd3-shape'
import {
areaY,
d3Curve,
defineChart,
dot,
lineY,
ruleY,
text,
} from '@tanstack/charts'
import { releases, weeks } from './activation-data'
import { activationTheme } from './activation-theme'
const monthDay = new Intl.DateTimeFormat('en-US', {
day: 'numeric',
month: 'short',
timeZone: 'UTC',
})
export const activationChart = defineChart({
marks: [
areaY(weeks, {
id: 'activation-range',
x: 'date',
y1: 'expectedLow',
y2: 'expectedHigh',
key: 'id',
fill: 'var(--activation-range)',
fillOpacity: 0.22,
curve: d3Curve(curveMonotoneX),
}),
ruleY([70], {
id: 'activation-goal',
stroke: 'var(--activation-goal)',
strokeOpacity: 0.95,
strokeWidth: 2,
strokeDasharray: '7 7',
}),
lineY(weeks, {
id: 'activation-line',
x: 'date',
y: 'activation',
key: 'id',
stroke: 'var(--activation-line)',
strokeWidth: 4.25,
points: true,
curve: d3Curve(curveMonotoneX),
}),
dot(releases, {
id: 'activation-events',
x: 'date',
y: 'activation',
key: 'id',
r: 6,
fill: 'var(--activation-bg)',
stroke: 'var(--activation-release)',
strokeWidth: 3,
}),
text(releases, {
id: 'activation-event-labels',
x: 'date',
y: 'activation',
text: 'label',
key: 'id',
fill: 'var(--activation-foreground)',
fontSize: 12,
fontWeight: 650,
dy: -21,
}),
],
x: {
scale: scaleUtc().domain([weeks[0]!.date, weeks.at(-1)!.date]),
axis: {
label: 'Week ending',
ticks: { format: (value) => monthDay.format(value) },
},
grid: false,
},
y: {
scale: scaleLinear().domain([40, 82]),
axis: {
label: 'Activation rate (%)',
ticks: { count: 5, format: (value) => `${Math.round(value)}%` },
},
grid: true,
},
theme: activationTheme,
})TanStack Charts builds on Leland Wilkinson's grammar of graphics and the work of ggplot2, Vega-Lite, and Observable Plot. Its marks-and-channels API is most directly inspired by Observable Plot, but the runtime is an independent implementation.
Partners
Sponsors get special perks like private discord channels, priority issue requests, and direct support!