A tiny TypeScript visualization grammar for responsive, accessible, server-rendered application charts.
Important
TanStack Charts is currently an unpublished 0.0.0 product proof. The packages
are not published or ready for production use yet.
Most chart libraries are easy until the chart stops being standard. TanStack Charts gives you one typed grammar that can grow from a familiar line or bar chart into a product-specific visualization without replacing your data model or dropping down to a separate API.
- Keep your data as it is. Marks consume arrays, objects, tuples, and iterables directly. Different layers can use different datum types.
- Bring native D3 primitives. Use D3 scales, curves, transforms, and layout output instead of relearning a parallel math API.
- Build from common to custom. Layer built-in marks or implement a custom mark against the same public scene protocol.
- Get the application runtime too. Responsive layout, automatic guide margins, themes, interaction, animation, accessibility, SVG SSR, opt-in Canvas painting, hydration, and export are part of the system.
- Pay for what you import. Marks, renderers, and chart-owned interactions
have independent TanStack subpaths; specialized algorithms come directly
from granular, tree-shakeable
d3-*packages.
import { max } from 'd3-array'
import { scaleBand, scaleLinear } from 'd3-scale'
import { barY, defineChart } from '@tanstack/charts'
import { Chart } from '@tanstack/react-charts'
const revenue = [
{ month: 'Jan', value: 42 },
{ month: 'Feb', value: 58 },
{ month: 'Mar', value: 76 },
{ month: 'Apr', value: 64 },
]
const revenueChart = defineChart({
marks: [
barY(revenue, {
x: 'month',
y: 'value',
}),
],
x: {
scale: scaleBand()
.domain(revenue.map((row) => row.month))
.padding(0.2),
},
y: {
scale: scaleLinear()
.domain([0, max(revenue, (row) => row.value) ?? 0])
.nice(),
label: 'Revenue',
grid: true,
},
})
export function RevenueChart() {
return (
<Chart
definition={revenueChart}
height={320}
ariaLabel="Monthly revenue"
tooltip
/>
)
}Marks consume the original rows, channels describe their visual encodings, and configured D3 scales own the domain and mapping. TanStack copies those scales, assigns their responsive pixel ranges, compiles a renderer-neutral keyed scene, and hands that scene to the selected host.
Definitions are framework-independent. The same revenueChart can render
through React, Octane, the vanilla DOM host, static SVG, or the optional Canvas
renderer.
When SVG element count becomes the bottleneck, switch the adapter import and keep the definition and interaction props:
import { Chart } from '@tanstack/react-charts/canvas'Canvas stays outside the default bundles. React and Octane also expose a
renderer-neutral /core entry when an application owns the surface. Canvas
removes per-mark DOM cost, not scene memory or dense nearest-point work, so
large interactive charts should still use a measured spatial index or a
bounded representation.
| Package | Role |
|---|---|
@tanstack/charts |
Marks, channels, guides, scene compilation, SVG, optional Canvas, vanilla DOM lifecycle, and export |
@tanstack/react-charts |
Thin React lifecycle adapter with SSR and hydration |
@tanstack/octane-charts |
Thin Octane lifecycle adapter with equivalent scene output |
The earlier host experiment remains under @plot-poc/* for migration evidence
and benchmark comparison. The private
@tanstack/charts-d3 package preserves a
superseded backend experiment.
TanStack Charts deliberately splits ownership:
| D3 owns | TanStack Charts owns |
|---|---|
| Scales, shapes, transforms, color, spatial math, and layouts | Marks, channels, responsive ranges, guide layout, scene compilation, rendering, and lifecycle |
This boundary keeps D3 visible and replaceable at the algorithm level while giving applications a consistent runtime. There is no global registry, library-owned dataframe, or chart-type configuration model.
TanStack Charts is an independent implementation. Its conceptual lineage and
the projects and people whose work informed it are credited in
ACKNOWLEDGEMENTS.md.
I designed TanStack Charts and directed its architecture, API, tradeoffs, and final decisions. Almost all of the implementation was produced with AI coding agents under my direct supervision, then reviewed and accepted into the project.
For live application state, defineChart<Input>() keeps expensive preparation
separate from visual construction and responsive layout. The definition drives
host prop and callback inference, so normal authoring does not require adapter
generics, mark-array annotations, or casts. See
Chart Definitions for the complete
pattern.
| Start here | Use it for |
|---|---|
docs/overview.md |
Product model, responsibilities, and defaults |
docs/quick-start.md |
First complete framework-agnostic chart |
docs/concepts/grammar-of-graphics.md |
Marks, channels, scales, and composition |
docs/concepts/scales-and-d3.md |
The D3 dependency and ownership boundary |
docs/examples/index.md |
Curated chart-family and interaction examples |
docs/guides/ai-authoring.md |
Deterministic authoring and validation for coding agents |
docs/reference/index.md |
Complete public API map |
llms.txt |
Generated documentation routing index |
Architecture decisions and open production gates live in
PLAN.md. Evidence from real authoring and migration work is
tracked in API-FRICTION.md.
- We welcome issues and pull requests.
- Chat with the community on Discord.
- Follow the project through the roadmap and conformance catalog.
|
|
|
We're looking for TanStack Charts Partners to join our mission! Partner with us to push the boundaries of TanStack Charts and build amazing things together.
LET'S CHAT- TanStack Config – Tooling for JS/TS packages
- TanStack DB – Reactive sync client store
- TanStack DevTools – Unified devtools panel
- TanStack Form – Type-safe form state
- TanStack Pacer – Debouncing, throttling, and batching
- TanStack Query – Async state and caching
- TanStack Ranger – Range and slider primitives
- TanStack Router – Type-safe routing, caching, and URL state
- TanStack Start – Full-stack SSR and streaming
- TanStack Store – Reactive data store
- TanStack Table – Headless datagrids
- TanStack Virtual – Virtualized rendering
… and more at TanStack.com »
The workspace requires Node.js 22 or newer and pnpm 11.
pnpm install
pnpm test
pnpm typecheck
pnpm build
pnpm package:checkRun a local example:
pnpm dev:charts-react
pnpm dev:charts-octane
pnpm dev:sandbox
pnpm dev:conformanceThe repository includes three complementary benchmark suites:
benchmarks/bundle-sizelocks ordinary consumer bundles and isolates optional feature costs.benchmarks/comparisoncompares equivalent line, bar, area, and scatter consumers across chart libraries, including a large-data and update stress matrix.benchmarks/conformanceexercises a broad, typed catalog against multiple reference renderers.
pnpm bundle:check
pnpm performance
pnpm benchmark:check
pnpm benchmark:stress:quick
pnpm conformance:quickThese measurements are development evidence, not release claims. See each suite's README for its protocol, output, and limitations.
Pull requests first gate formatting, types, tests, packed exports and declarations, locked bundles, comparison bundles, and catalog metadata. Browser comparison, all 79 conformance cases, and the quick five-library stress matrix then run as separate artifact-producing jobs.
MIT © Tanner Linsley. See
ACKNOWLEDGEMENTS.md for project lineage.
