Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ Add a changeset for every user-visible package change:
pnpm changeset
```

All eleven public Charts packages release as one fixed version. Documentation,
All twelve public Charts packages release as one fixed version. Documentation,
tests, benchmarks, and build-only changes do not need a changeset unless they
change the published package contract.
1 change: 1 addition & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@tanstack/charts",
"@tanstack/charts-scales",
"@tanstack/react-charts",
"@tanstack/react-native-charts",
"@tanstack/octane-charts",
"@tanstack/preact-charts",
"@tanstack/vue-charts",
Expand Down
8 changes: 8 additions & 0 deletions .changeset/native-svg-host.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@tanstack/react-native-charts': minor
---

Add the experimental React Native SVG host with responsive scene rendering,
focus, selection, accessibility actions, and an optional native tooltip entry.
Ship compiled ESM and declarations, and verify the packed package in bare React
Native and Expo Metro consumers.
3 changes: 3 additions & 0 deletions .github/workflows/chart-library-benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
- name: Run cached validation graph
run: pnpm run validate

- name: Check React Native POC types
run: pnpm react-native:poc:types

- name: Upload production catalog
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ dist
.benchmark-output
.catalog-artifact
.release-artifacts
.expo/
.nx/cache
.nx/workspace-data
coverage
Expand Down
258 changes: 241 additions & 17 deletions API-FRICTION.md

Large diffs are not rendered by default.

874 changes: 874 additions & 0 deletions NATIVE-PLATFORM-SUPPORT-SPIKE.md

Large diffs are not rendered by default.

426 changes: 426 additions & 0 deletions REACT-NATIVE-HOST-POC.md

Large diffs are not rendered by default.

25 changes: 13 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,19 @@ bounded representation.

## Packages

| Package | Role |
| ------------------------------------------------------- | ------------------------------------- |
| [`@tanstack/charts`](./packages/charts-core) | Framework-neutral grammar and runtime |
| [`@tanstack/react-charts`](./packages/react-charts) | React adapter |
| [`@tanstack/preact-charts`](./packages/preact-charts) | Preact adapter |
| [`@tanstack/vue-charts`](./packages/vue-charts) | Vue adapter |
| [`@tanstack/solid-charts`](./packages/solid-charts) | Solid adapter |
| [`@tanstack/svelte-charts`](./packages/svelte-charts) | Svelte adapter |
| [`@tanstack/angular-charts`](./packages/angular-charts) | Angular standalone-component adapter |
| [`@tanstack/lit-charts`](./packages/lit-charts) | Lit custom-element adapter |
| [`@tanstack/alpine-charts`](./packages/alpine-charts) | Alpine directive adapter |
| [`@tanstack/octane-charts`](./packages/octane-charts) | Octane adapter |
| Package | Role |
| ----------------------------------------------------------------- | ------------------------------------- |
| [`@tanstack/charts`](./packages/charts-core) | Framework-neutral grammar and runtime |
| [`@tanstack/react-charts`](./packages/react-charts) | React adapter |
| [`@tanstack/react-native-charts`](./packages/react-native-charts) | Experimental React Native SVG adapter |
| [`@tanstack/preact-charts`](./packages/preact-charts) | Preact adapter |
| [`@tanstack/vue-charts`](./packages/vue-charts) | Vue adapter |
| [`@tanstack/solid-charts`](./packages/solid-charts) | Solid adapter |
| [`@tanstack/svelte-charts`](./packages/svelte-charts) | Svelte adapter |
| [`@tanstack/angular-charts`](./packages/angular-charts) | Angular standalone-component adapter |
| [`@tanstack/lit-charts`](./packages/lit-charts) | Lit custom-element adapter |
| [`@tanstack/alpine-charts`](./packages/alpine-charts) | Alpine directive adapter |
| [`@tanstack/octane-charts`](./packages/octane-charts) | Octane adapter |

The earlier host experiment remains under `@plot-poc/*` for migration evidence
and benchmark comparison. The private
Expand Down
6 changes: 3 additions & 3 deletions benchmarks/comparison/bundle-baseline.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"schemaVersion": 3,
"generatedAt": "2026-08-01T17:40:25.541Z",
"generatedAt": "2026-08-01T18:25:10.144Z",
"packageVersions": {
"tanstack": "0.3.1",
"tanstack": "0.4.0",
"chartjs": "4.5.1",
"echarts": "6.1.0",
"recharts": "3.10.1",
Expand All @@ -11,7 +11,7 @@
"sources": {
"tanstack": {
"kind": "workspace",
"revision": "d563eba5d295dc3ddf60eecd2d8a9bd418aaf635"
"revision": "1a8b888822bb94be75b6416979d671a04218fe02"
},
"chartjs": {
"kind": "package",
Expand Down
11 changes: 11 additions & 0 deletions benchmarks/entries/charts-react-native-line.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { scaleLinear } from 'd3-scale'
import { lineY } from '@tanstack/charts/line'
import { defineChart } from '@tanstack/charts/scene'

export { Chart } from '@tanstack/react-native-charts'

export const definition = defineChart({
marks: [lineY([4, 9, 7])],
x: { scale: scaleLinear().domain([0, 2]) },
y: { scale: scaleLinear().domain([0, 10]) },
})
2 changes: 2 additions & 0 deletions benchmarks/entries/charts-react-native-tooltip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Chart } from '@tanstack/react-native-charts'
export { tooltip } from '@tanstack/react-native-charts/tooltip'
1 change: 1 addition & 0 deletions benchmarks/entries/charts-react-native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Chart } from '@tanstack/react-native-charts'
13 changes: 7 additions & 6 deletions docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ description: Compare TanStack Charts with measured and documentation-reviewed ch
---

TanStack Charts `0.4.0` is a pre-alpha release. Its results on this page measure
the exact workspace source included in this release and pinned competitor
packages. This comparison records architectural differences and reproducible
evidence without turning untested behavior into a checkmark.
the current workspace source and pinned competitor packages. This comparison
records architectural differences and reproducible evidence without turning
untested behavior into a checkmark.

## Tested versions

| Library | Package | Measured source |
| -------------------------------------------------------------------------------------- | -------------------- | ------------------- |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `d563eba` |
| [TanStack Charts](./overview.md) | `@tanstack/charts` | workspace `1a8b888` |
| [Chart.js](https://www.chartjs.org/docs/latest/) | `chart.js` | npm `4.5.1` |
| [Apache ECharts](https://echarts.apache.org/handbook/en/best-practices/canvas-vs-svg/) | `echarts` | npm `6.1.0` |
| [Recharts](https://recharts.github.io/en-US/) | `recharts` | npm `3.10.1` |
| [Observable Plot](https://observablehq.com/plot/features/plots) | `@observablehq/plot` | npm `0.6.17` |

The competitor versions are exact package pins, not latest versions inferred
at page render time. The measured TanStack workspace revision is `d563eba`.
at page render time. The measured TanStack workspace revision is `1a8b888`.

## Capability matrix

Expand Down Expand Up @@ -170,7 +170,8 @@ Canvas composition while keeping D3 and state ownership explicit.
## Evidence and reproduction

- [Standard comparison protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/README.md)
- [Tracked bundle baseline](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/bundle-baseline.json)
- [Current tracked bundle baseline](https://github.com/TanStack/charts/blob/main/benchmarks/comparison/bundle-baseline.json)
- [0.4.0 tagged bundle baseline](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/bundle-baseline.json)
- [Stress protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/comparison/stress/README.md)
- [Catalog conformance protocol](https://github.com/TanStack/charts/blob/v0.4.0/benchmarks/conformance/README.md)

Expand Down
59 changes: 48 additions & 11 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Then add one adapter if the application needs it:
# React
pnpm add @tanstack/react-charts react react-dom

# React Native
pnpm add @tanstack/react-native-charts react react-native react-native-svg

# Preact
pnpm add @tanstack/preact-charts preact

Expand Down Expand Up @@ -46,22 +49,56 @@ The adapters intentionally do not replace the core package. Definitions and mark

## Framework compatibility

| Adapter package | Framework peers |
| -------------------------- | ---------------------------------------- |
| `@tanstack/react-charts` | React and React DOM `^19.0.0` |
| `@tanstack/preact-charts` | Preact `>=10` |
| `@tanstack/vue-charts` | Vue `>=3.5` |
| `@tanstack/solid-charts` | Solid `>=1.8` |
| `@tanstack/svelte-charts` | Svelte `^5.20.0` |
| `@tanstack/angular-charts` | Angular core and platform browser `>=19` |
| `@tanstack/lit-charts` | Lit `>=3.1.3` |
| `@tanstack/alpine-charts` | Alpine `>=3.15` |
| `@tanstack/octane-charts` | Octane `^0.1.13` |
| Adapter package | Framework peers |
| ------------------------------- | ------------------------------------------------------------------------------- |
| `@tanstack/react-charts` | React and React DOM `^19.0.0` |
| `@tanstack/react-native-charts` | React `^19.2.3`, React Native `^0.86.0`, and `react-native-svg` `>=15.15.4 <16` |
| `@tanstack/preact-charts` | Preact `>=10` |
| `@tanstack/vue-charts` | Vue `>=3.5` |
| `@tanstack/solid-charts` | Solid `>=1.8` |
| `@tanstack/svelte-charts` | Svelte `^5.20.0` |
| `@tanstack/angular-charts` | Angular core and platform browser `>=19` |
| `@tanstack/lit-charts` | Lit `>=3.1.3` |
| `@tanstack/alpine-charts` | Alpine `>=3.15` |
| `@tanstack/octane-charts` | Octane `^0.1.13` |

These ranges are the package peer contracts. Use the selected framework's
normal renderer or application package beside the adapter when the application
needs browser mounting or server rendering.

## React Native and Expo

The React Native adapter is experimental and renders through
`react-native-svg`. Expo 57 applications can install the package and the SVG
version selected by Expo:

```sh
pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale
pnpm exec expo install react-native-svg
```

Bare React Native 0.86 applications install the renderer directly:

```sh
pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale react-native-svg
```
Comment on lines +80 to +84

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

jq -r '.peerDependencies["react-native-svg"]' packages/react-native-charts/package.json
rg -n -C 2 'react-native-svg' docs/installation.md examples/charts-react-native/package.json examples/charts-expo/package.json
printf 'Unqualified registry version: '
pnpm view react-native-svg version

Repository: TanStack/charts

Length of output: 2855


Pin react-native-svg in the bare React Native install command.

@tanstack/react-native-charts requires react-native-svg >=15.15.4 <16, but the bare command installs the unqualified latest, which can resolve an incompatible major version. Use a version specifier that stays in the declared peer range, such as react-native-svg@^15.15.4, and leave Expo installs with expo install so Expo picks its compatible native version.

Suggested documentation fix
- pnpm add `@tanstack/charts` `@tanstack/react-native-charts` d3-scale react-native-svg
+ pnpm add `@tanstack/charts` `@tanstack/react-native-charts` d3-scale react-native-svg@^15.15.4
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Bare React Native 0.86 applications install the renderer directly:
```sh
pnpm add @tanstack/charts @tanstack/react-native-charts d3-scale react-native-svg
```
Bare React Native 0.86 applications install the renderer directly:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/installation.md` around lines 80 - 84, Update the bare React Native
installation command in the installation documentation to pin react-native-svg
to a version within `@tanstack/react-native-charts`’ peer range, such as ^15.15.4.
Leave the Expo installation command using expo install unchanged.


Run `bundle exec pod install` from `ios/` after adding it to a bare iOS
application. Import shared definitions through the universal entry and choose
the native host explicitly:

```tsx
import { defineChart, lineY } from '@tanstack/charts/universal'
import { Chart } from '@tanstack/react-native-charts'
import { tooltip } from '@tanstack/react-native-charts/tooltip'
```

Packed tarballs are typechecked and bundled through default bare React Native
and Expo Metro configurations on iOS and Android. The workspace Expo 57
fixture also renders in Expo Go on an iOS simulator. Bare-native and Android
simulators, physical devices, gestures, visual parity, and screen readers are
not yet support claims.
Comment on lines +96 to +100

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the support-claim wording.

The sentence says are not yet support claims. Replace it with are outside the current support claims or are not currently supported. The current wording is ungrammatical and ambiguous for users.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/installation.md` around lines 96 - 100, Update the support-claim
sentence in the installation documentation to replace “are not yet support
claims” with clear wording such as “are outside the current support claims” or
“are not currently supported,” while preserving the listed platform and
capability scope.


## Install the D3 modules you import

TanStack Charts accepts D3 scale factories, configured scale instances, and
Expand Down
30 changes: 16 additions & 14 deletions docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ The library is designed for two equally important authors:
- People should get polished, responsive charts from a short declaration.
- AI should be able to compose, inspect, and modify charts without learning an application-specific series model or guessing at hidden behavior.

The same definition works with the vanilla DOM host and every framework
adapter. React and Octane also provide optional Canvas entries.
The same definition can feed the vanilla DOM host and framework adapters.
React and Octane also provide optional Canvas entries; the experimental React
Native adapter consumes definitions from the universal entry.

## A chart is a composition

Expand Down Expand Up @@ -156,18 +157,19 @@ Every automatic behavior has an explicit escape hatch. The [Guides](./guides/res

## Packages

| Package | Use it for |
| -------------------------- | ---------------------------------------------------------------- |
| `@tanstack/charts` | Definitions, marks, scenes, SVG, Canvas, export, and vanilla DOM |
| `@tanstack/react-charts` | React `<Chart>` |
| `@tanstack/preact-charts` | Preact `<Chart>` |
| `@tanstack/vue-charts` | Vue `<Chart>` |
| `@tanstack/solid-charts` | Solid `<Chart>` |
| `@tanstack/svelte-charts` | Svelte `<Chart>` |
| `@tanstack/angular-charts` | Angular `<tanstack-chart>` |
| `@tanstack/lit-charts` | Lit `<tanstack-chart>` |
| `@tanstack/alpine-charts` | Alpine `x-chart` |
| `@tanstack/octane-charts` | Octane `<Chart>` |
| Package | Use it for |
| ------------------------------- | ---------------------------------------------------------------- |
| `@tanstack/charts` | Definitions, marks, scenes, SVG, Canvas, export, and vanilla DOM |
| `@tanstack/react-charts` | React `<Chart>` |
| `@tanstack/react-native-charts` | Experimental React Native SVG `<Chart>` |
| `@tanstack/preact-charts` | Preact `<Chart>` |
| `@tanstack/vue-charts` | Vue `<Chart>` |
| `@tanstack/solid-charts` | Solid `<Chart>` |
| `@tanstack/svelte-charts` | Svelte `<Chart>` |
| `@tanstack/angular-charts` | Angular `<tanstack-chart>` |
| `@tanstack/lit-charts` | Lit `<tanstack-chart>` |
| `@tanstack/alpine-charts` | Alpine `x-chart` |
| `@tanstack/octane-charts` | Octane `<Chart>` |

All packages are ESM and tree-shakeable. Built-in marks and optional capabilities also have subpath exports when a library or design system needs tighter bundle boundaries.

Expand Down
44 changes: 44 additions & 0 deletions examples/charts-expo/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react'
import { SafeAreaView, View } from 'react-native'
import { scaleLinear } from 'd3-scale'
import { defineChart, lineY } from '@tanstack/charts/universal'
import { Chart } from '@tanstack/react-native-charts'
import { tooltip } from '@tanstack/react-native-charts/tooltip'

const rows = [
{ month: 1, revenue: 12 },
{ month: 2, revenue: 18 },
{ month: 3, revenue: 15 },
{ month: 4, revenue: 26 },
{ month: 5, revenue: 31 },
]

const definition = defineChart({
marks: [
lineY(rows, {
x: 'month',
y: 'revenue',
stroke: '#2563eb',
strokeWidth: 3,
points: true,
}),
],
x: { label: 'Month', scale: scaleLinear().domain([1, 5]) },
y: { label: 'Revenue', scale: scaleLinear().domain([0, 35]) },
focus: 'nearest-x',
tooltip: { use: tooltip, sticky: true },
})

export default function App() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: '#f8fafc' }}>
<View style={{ flex: 1, padding: 16, justifyContent: 'center' }}>
<Chart
definition={definition}
accessibilityLabel="Monthly revenue"
aspectRatio={1.5}
/>
</View>
</SafeAreaView>
)
}
6 changes: 6 additions & 0 deletions examples/charts-expo/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"expo": {
"name": "TanStack Charts Expo",
"slug": "tanstack-charts-expo"
}
}
4 changes: 4 additions & 0 deletions examples/charts-expo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { registerRootComponent } from 'expo'
import App from './App'

registerRootComponent(App)
3 changes: 3 additions & 0 deletions examples/charts-expo/metro.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { getDefaultConfig } = require('expo/metro-config')

module.exports = getDefaultConfig(__dirname)
28 changes: 28 additions & 0 deletions examples/charts-expo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@charts-poc/expo-example",
"version": "0.0.0",
"private": true,
"license": "MIT",
"main": "index.ts",
"scripts": {
"start": "expo start",
"bundle": "expo export --platform all --output-dir dist --clear"
},
"dependencies": {
"@tanstack/charts": "workspace:*",
"@tanstack/react-native-charts": "workspace:*",
"d3-scale": "4.0.2",
"expo": "~57.0.9",
"react": "19.2.3",
"react-native": "0.86.2",
"react-native-svg": "15.15.4"
},
"devDependencies": {
"@types/d3-scale": "^4.0.9",
"@types/react": "~19.2.2",
"typescript": "~6.0.3"
},
"engines": {
"node": ">=22.13.0"
}
}
8 changes: 8 additions & 0 deletions examples/charts-expo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"skipLibCheck": true
},
"include": ["App.tsx", "index.ts"]
}
10 changes: 10 additions & 0 deletions examples/charts-react-native/App.granular.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as React from 'react'
import { lineY } from '@tanstack/charts/line'
import { defineChart } from '@tanstack/charts/scene'
import { createRevenueDefinition, RevenueChart } from './RevenueChart'

const definition = createRevenueDefinition(defineChart, lineY)

export default function GranularApp() {
return <RevenueChart definition={definition} />
}
9 changes: 9 additions & 0 deletions examples/charts-react-native/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as React from 'react'
import { defineChart, lineY } from '@tanstack/charts/universal'
import { createRevenueDefinition, RevenueChart } from './RevenueChart'

const definition = createRevenueDefinition(defineChart, lineY)

export default function App() {
return <RevenueChart definition={definition} />
}
Loading