TanStack
TanStack

Charts

A chart grammar you don't have to outgrow.

TanStack Charts 0.1.0 is on npm. Install @tanstack/charts for vanilla TypeScript or add the 0.1.0 adapter for React, Vue, Svelte, Solid, Angular, Preact, Lit, Alpine, or Octane.

Docs
Data
productSignals · 8 rows
Marks
areaY + ruleY + lineY + dot + text
Scales
linear × linear
const releases = productSignals.filter(
  (row) => row.product === 'Form' || row.product === 'Store',
)

export const kineticLayeredChart = defineChart({
  marks: [
    areaY(productSignals, {
      id: 'hero-area',
      x: 'month',
      y1: 'previous',
      y2: 'forecast',
      key: 'id',
      fill: '#3aa3c4',
      fillOpacity: 0.24,
      curve: d3Curve(curveMonotoneX),
    }),
    ruleY([70], {
      id: 'hero-rule',
      stroke: '#e06e49',
      strokeWidth: 2,
      strokeDasharray: '7 7',
    }),
    lineY(productSignals, {
      id: 'hero-line',
      x: 'month',
      y: 'value',
      key: 'id',
      stroke: '#61adbf',
      strokeWidth: 3,
      curve: d3Curve(curveMonotoneX),
    }),
    dot(productSignals, {
      id: 'hero-points',
      x: 'month',
      y: 'value',
      z: 'segment',
      key: 'id',
      stroke: '#9cd5e2',
      strokeWidth: 2,
      r: 4,
    }),
    text(releases, {
      id: 'hero-labels',
      x: 'month',
      y: 'value',
      text: 'product',
      key: 'id',
      fill: '#ffffff',
      fontSize: 11,
      fontWeight: 650,
      dy: -18,
    }),
  ],
  x: {
    scale: scaleLinear().domain([1, 8]),
    axis: { ticks: { count: 4, format: (month) => `M${month}` } },
  },
  y: {
    scale: scaleLinear().domain([30, 100]),
    axis: { ticks: { count: 4 } },
    grid: true,
  },
  theme: kineticDarkTheme,
})

Agents write the chart. TypeScript checks the result.

Every example compiles under strict TypeScript. Fields, datum types, inferred domains and keys, tooltips, and focus callbacks stay connected to the source datum; the type suite rejects invalid definitions.

Example prompt

Plot monthly revenue against retention. Size each account by seats, color it by segment, add tooltips, and keep the Account type in every callback.

Account → SVG
dot(accounts, {
 x: 'monthlyRevenue',
 y: 'retention',
 r: 'seats',
 z: 'segment',
})

Account health

Example account dataset · Q2 2026

Which high-revenue accounts need retention attention?

EnterpriseGrowthSMBBubble size = seats
Illustrative account data. Horizontal position shows monthly revenue in thousands of dollars, vertical position shows 90-day retention, color distinguishes SMB, Growth, and Enterprise segments, and bubble area represents account count.

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

Complete SVG charts. 24.2–24.8 KiB gzip.

Measured minified and gzipped from one-series charts in the reproducible comparison suite. Granular imports leave unrelated marks and D3 modules out.

Common chart bundles

Minified + gzip

Weekly revenue by product

One definition · two container sizes

Wide container900 × 420
Illustrative weekly revenue data from January through April 2026. Three product lines share the same date and revenue scales.
Compact container420 × 420
Illustrative weekly revenue data from January through April 2026. Three product lines share the same date and revenue scales.

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

ActivationExpected rangeGoalReleases
Illustrative weekly activation data from January through May 2026. The actual rate rises from 48 to 78 percent, compared with an expected range and a 70 percent goal. Onboarding v2 and Invite flow are marked as release events.
activation-chart.ts
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: '#3aa3c4',
      fillOpacity: 0.2,
      curve: d3Curve(curveMonotoneX),
    }),
    ruleY([70], {
      id: 'activation-goal',
      stroke: '#e06e49',
      strokeOpacity: 0.95,
      strokeWidth: 2,
      strokeDasharray: '7 7',
    }),
    lineY(weeks, {
      id: 'activation-line',
      x: 'date',
      y: 'activation',
      key: 'id',
      stroke: '#61adbf',
      strokeWidth: 3.25,
      points: true,
      curve: d3Curve(curveMonotoneX),
    }),
    dot(releases, {
      id: 'activation-events',
      x: 'date',
      y: 'activation',
      key: 'id',
      r: 6,
      fill: '#ffffff',
      stroke: '#3aa3c4',
      strokeWidth: 3,
    }),
    text(releases, {
      id: 'activation-event-labels',
      x: 'date',
      y: 'activation',
      text: 'label',
      key: 'id',
      fill: '#ffffff',
      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

Gold
Lovable
CodeRabbit
Cloudflare
Netlify
Railway
Silver
SerpApi
AG Grid
OpenRouter
WorkOS
Clerk
Bronze
Electric
Sentry
Prisma
Unkey
OSS Sponsors

Sponsors get special perks like private discord channels, priority issue requests, and direct support!