TanStack Charts
TanStack Charts no es un catálogo de tipos de gráfica («dame un bar chart con estas opciones»), sino una gramática: describes la gráfica como capas de marks (barras, líneas, puntos) que leen tus datos tal cual, con canales que dicen qué campo va a cada eje y escalas que traducen valores a píxeles. Es el modelo de Observable Plot y Vega-Lite, con tipos de TypeScript inferidos de tus datos.
Lo crea Tanner Linsley, autor de TanStack Query y TanStack Table. Él mismo lo declara en el README: diseñó la arquitectura y la API, y casi toda la implementación la escribieron agentes de IA bajo su supervisión.
En pocas palabras
Sección titulada «En pocas palabras»- SVG por defecto, con renderizado en servidor (SSR) e hidratación. Canvas opcional para series densas.
- Una definición, cualquier framework. La misma
defineChart(...)se pinta con React, Preact, Vue, Solid, Svelte, Angular, Lit, Alpine, Octane, React Native o el DOM sin framework. - Pagas lo que importas. Cada escala, interacción y renderer vive en su propio subpath; según su suite de medición, un consumidor típico ocupa entre 43 y 50 kB gzip.
- Accesibilidad, tooltips, ejes y márgenes automáticos incluidos. La animación (tween y muelle) es un renderer aparte y opcional.
Instalación
Sección titulada «Instalación»Un solo paquete; el framework va como peer:
# Reactpnpm add @tanstack/charts react react-dom
# Vuepnpm add @tanstack/charts vue
# Sveltepnpm add @tanstack/charts svelte
# Solidpnpm add @tanstack/charts solid-js
# Angularpnpm add @tanstack/charts @angular/core @angular/platform-browser# Reactbun add @tanstack/charts react react-dom
# Vuebun add @tanstack/charts vue
# Sveltebun add @tanstack/charts svelte
# Solidbun add @tanstack/charts solid-js
# Angularbun add @tanstack/charts @angular/core @angular/platform-browser# Reactnpm install @tanstack/charts react react-dom
# Vuenpm install @tanstack/charts vue
# Sveltenpm install @tanstack/charts svelte
# Solidnpm install @tanstack/charts solid-js
# Angularnpm install @tanstack/charts @angular/core @angular/platform-browserLas piezas se importan por subpath exacto: @tanstack/charts/react, @tanstack/charts/scales/linear, @tanstack/charts/tooltip… No hay un export agregado de escalas, a propósito.
Conceptos
Sección titulada «Conceptos»| Concepto | Qué es | Ejemplo |
|---|---|---|
| Mark | Una capa geométrica que consume un array de filas | barY, lineY, areaY, dot |
| Canal | Qué valor de cada fila va a cada propiedad visual. Puede ser el nombre de un campo o una función (accessor) | x: 'month', y: (d) => d.total / 1000 |
| Escala | Traduce el dominio de los datos a píxeles. El dominio se infiere de los canales; el rango lo pone el tamaño de la gráfica | scaleLinear, scaleBand, scalePoint |
| Eje / guía | Se configura dentro de la escala: rejilla, etiqueta, formato de ticks | axis: { label: 'Ingresos' }, grid: true |
| Serie | Agrupación dentro de un mark con z o color | lineY(rows, { x, y, color: 'serie' }) |
| Definición | El objeto que junta marks, escalas y capacidades; es independiente del framework | defineChart({ marks, scales, tooltip }) |
Las escalas propias de TanStack cubren lo común (lineal, banda, punto, ordinal) sin dependencia de D3. Para fechas, logarítmicas u otras, pasas directamente la escala de d3-scale (scaleUtc, scaleLog…), que entonces instalas tú.
Los marks básicos son barY/barX, lineY/lineX, areaY/areaX y dot; por subpaths aparte hay polares, mapas, sankey, treemap, sunburst, contornos, violines y más.
Ejemplo completo en React
Sección titulada «Ejemplo completo en React»import { barY, defineChart } from "@tanstack/charts"import { scaleBand } from "@tanstack/charts/scales/band"import { scaleLinear } from "@tanstack/charts/scales/linear"import { tooltip } from "@tanstack/charts/tooltip"import { Chart } from "@tanstack/charts/react"
const revenue = [ { month: "Ene", value: 42 }, { month: "Feb", value: 58 }, { month: "Mar", value: 76 }, { month: "Abr", value: 64 }]
// A nivel de módulo: la definición no cambia entre rendersconst revenueChart = defineChart({ marks: [barY(revenue, { x: "month", y: "value" })], scales: { x: { scale: () => scaleBand().padding(0.2) }, y: { scale: scaleLinear, nice: true, grid: true, axis: { label: "Ingresos (miles)" } } }, tooltip})
export function RevenueChart() { return <Chart definition={revenueChart} height={320} ariaLabel="Ingresos mensuales" />}Puntos a notar:
- El tipo de cada fila se infiere de
revenue; no hacen falta genéricos ni casts. - Con
heightfijo, el ancho sigue al contenedor. Alternativa:aspectRatio={16 / 9}coninitialWidthpara el SSR. ariaLabeles obligatorio en la práctica: es lo que lee un lector de pantalla.- Si la definición depende de props o estado, envuélvela entera en
useMemo. La identidad de la definición es lo que dispara la actualización.
Ejemplo en Vue
Sección titulada «Ejemplo en Vue»Una gráfica de líneas con dos series, reactiva a los datos:
<script setup lang="ts">import { computed, ref } from "vue"import { defineChart, lineY } from "@tanstack/charts"import { scaleLinear } from "@tanstack/charts/scales/linear"import { scalePoint } from "@tanstack/charts/scales/point"import { tooltip } from "@tanstack/charts/tooltip"import { Chart } from "@tanstack/charts/vue"
const rows = ref([ { day: "Lun", source: "Orgánico", visits: 120 }, { day: "Mar", source: "Orgánico", visits: 150 }, { day: "Mié", source: "Orgánico", visits: 140 }, { day: "Lun", source: "Redes", visits: 80 }, { day: "Mar", source: "Redes", visits: 95 }, { day: "Mié", source: "Redes", visits: 130 }])
const definition = computed(() => defineChart({ marks: [lineY(rows.value, { x: "day", y: "visits", color: "source", points: true })], scales: { x: { scale: scalePoint }, y: { scale: scaleLinear, nice: true, grid: true, axis: { label: "Visitas" } } }, tooltip }))</script>
<template> <Chart :definition="definition" aria-label="Visitas por fuente" :aspect-ratio="16 / 9" /></template>color: 'source' agrupa las filas en una línea por fuente y les asigna color. En Vue, una definición que captura estado reactivo va en computed; una estática, a nivel de módulo. El componente renderiza el SVG en el servidor con Vue SSR.
En Svelte 5 el patrón es el mismo con $derived(defineChart(...)) y <Chart {definition} ariaLabel="…" /> desde @tanstack/charts/svelte.
Animación y Canvas
Sección titulada «Animación y Canvas»Ambos son opcionales y no entran en el bundle si no los importas:
- Animación:
motion()desde@tanstack/charts/motionreemplaza el renderer SVG por uno con transiciones tween o de muelle; respetaprefers-reduced-motionpor defecto. - Canvas: cambiar
@tanstack/charts/reactpor@tanstack/charts/react/canvasmantiene la definición y quita el coste de un nodo DOM por punto. También se puede aplicar Canvas solo a un mark denso dentro de una gráfica SVG.
Comparativa
Sección titulada «Comparativa»Cifras de bundle de la propia página de comparación de TanStack (medidas por ellos, minificado + gzip, gráficas de línea, barra, área y dispersión):
| TanStack Charts | Chart.js | Recharts | Apache ECharts | |
|---|---|---|---|---|
| Salida | SVG por defecto, Canvas opcional | Solo Canvas | SVG | Canvas por defecto, SVG opcional |
| Frameworks | Núcleo neutro + adaptadores | Núcleo neutro (wrappers de la comunidad) | Solo React | Núcleo neutro |
| Modelo | Gramática (marks + escalas) | Configuración por tipo de gráfica | Componentes JSX | Configuración declarativa por series |
| Bundle medido | 43–50 kB | 46–60 kB | 157–172 kB (97–113 kB sin contar React) | 157–177 kB |
| Licencia | MIT | MIT | MIT | Apache-2.0 |
- Elige TanStack Charts si necesitas gráficas que salgan de lo estándar, SSR real, inspección y estilado con CSS, o la misma definición en varios frameworks.
- Elige Chart.js si quieres una gráfica estándar rápido, con miles de ejemplos en internet, y no te importa el canvas.
- Elige Recharts si todo es React y prefieres componentes JSX a una gramática.
- Elige ECharts para dashboards muy densos, mapas o volúmenes enormes de datos donde su canvas y sus decenas de tipos listos compensan el tamaño.
La comparación la publica TanStack: tómala como punto de partida y mide en tu propia app.
Límites
Sección titulada «Límites»- Recién estable. La 1.0 es de octubre de 2026; el ecosistema de ejemplos y respuestas en internet todavía es pequeño, y gran parte del material existente es de la etapa alfa.
- Curva de aprendizaje. Pensar en marks y escalas cuesta más al principio que elegir
type: 'bar'; la recompensa llega cuando la gráfica se sale del molde. - SVG tiene techo. Con miles de puntos interactivos, pasa a Canvas o reduce los datos.
- Escrito casi entero por IA, según su autor. Tiene una suite de verificación extensa, pero conviene saberlo al evaluar riesgos.