Charts
A chart grammar you don't have to outgrow.
TanStack Charts 0.3.1 is on npm. A compact React line consumer is 16.48 KiB gzip; its framework-neutral scene is 8.12 KiB.
All mark, no chart.
Just a few examples. The possibilities are endless.
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
16.48 KiB for a compact React line.
The framework-neutral scene is 8.12 KiB and retains neither D3 nor InternMap. For an apples-to-apples comparison, the pinned 12-case suite measures full cold-page browser bundles; Bklit's interactive line is included alongside the published library ranges.
Cold-page bundle comparison
Published 12-chart ranges; Bklit is an interactive line · minified + gzip
Layer marks over shared scales.
Area, rules, lines, points, and labels share one coordinate system. The definition beside the chart is the whole composition.
Weekly activation rate
Jan–May 2026 · illustrative product telemetry
78%
above 70% goal
import { curveMonotoneX, scaleLinear, scaleUtc } from 'd3'
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!