TanStack
Getting Started

Quick Start

This walkthrough uses the framework-agnostic DOM host. The same chart definition passes unchanged to any supported framework adapter.

1. Add a chart container

html
<div id="revenue-chart"></div>

The host follows the container width when width is omitted.

2. Define the data and chart

ts
import { scaleLinear, scaleUtc } from 'd3-scale'
import { defineChart, lineY, mountChart } from '@tanstack/charts'

interface RevenueRow {
  id: string
  date: Date
  revenue: number | null
}

const rows: readonly RevenueRow[] = [
  { id: '2026-01', date: new Date('2026-01-01T00:00:00Z'), revenue: 38_000 },
  { id: '2026-02', date: new Date('2026-02-01T00:00:00Z'), revenue: 44_500 },
  { id: '2026-03', date: new Date('2026-03-01T00:00:00Z'), revenue: null },
  { id: '2026-04', date: new Date('2026-04-01T00:00:00Z'), revenue: 51_200 },
  { id: '2026-05', date: new Date('2026-05-01T00:00:00Z'), revenue: 57_800 },
]

const revenueChart = defineChart({
  marks: [
    lineY(rows, {
      id: 'monthly-revenue',
      x: 'date',
      y: 'revenue',
      stroke: '#2563eb',
      points: true,
    }),
  ],
  x: {
    scale: scaleUtc,
    nice: true,
    label: 'Month',
  },
  y: {
    scale: scaleLinear,
    nice: true,
    label: 'Revenue',
    format: (value) =>
      new Intl.NumberFormat(undefined, {
        style: 'currency',
        currency: 'USD',
        notation: 'compact',
        maximumFractionDigits: 1,
      }).format(value),
    grid: true,
  },
  tooltip: true,
})

Because this source imports d3-scale directly, add it and @types/d3-scale as direct dependencies. See Installation.

The missing March value creates a break instead of a misleading segment. The datum type flows through the mark and into interaction callbacks; no cast or manual chart generic is needed.

3. Mount it

ts
const container = document.querySelector<HTMLElement>('#revenue-chart')

if (!container) {
  throw new Error('Missing #revenue-chart container')
}

const options = {
  definition: revenueChart,
  height: 360,
  initialWidth: 640,
  ariaLabel: 'Monthly revenue from January through May 2026',
  ariaDescription: 'March has no reported value.',
}

const host = mountChart(container, options)

initialWidth is the deterministic fallback for server output, hidden containers, and the first frame before measurement. Once visible, the host uses ResizeObserver to follow the container.

4. Update the chart

Host options only cover mounting concerns such as size and accessibility:

ts
host.update({
  ...options,
  height: 420,
})

When data, visual options, focus, tooltips, keyboard policy, or animation change, create a new definition and pass it to host.update. In a framework component, memoize the complete definition against the values it captures. See Chart definitions.

5. Clean up

ts
host.destroy()

Destroying the host removes observers, event listeners, animations, tooltips, and chart markup. Framework adapters do this automatically during unmount.

What the declaration means

  • lineY(rows, ...) chooses a line mark and keeps the original row as the interaction datum.
  • x: 'date' and y: 'revenue' map typed fields to positional channels.
  • The unique row id gives each observation stable identity across updates.
  • D3 scale factories infer domains from mark channels and own mapping behavior.
  • TanStack Charts copies those scales and assigns responsive pixel ranges.
  • label, format, and grid configure the axis guide without changing the scale.
  • Omitted margins are measured automatically from the rendered labels and titles.
  • ariaLabel names the chart; pointer and keyboard focus use the same inferred points.

Read Grammar of Graphics for the full model, then browse the Example Gallery for complete compositions.