@tanstack/charts
Version:
A chart grammar for TypeScript and JavaScript. Marks consume your data directly, channels describe visual encodings, and the engine compiles them into a renderer-neutral keyed scene. TanStack's compact scales cover common numeric and categorical mappings.
226 lines (150 loc) • 8.47 kB
Markdown
name: ship-accessible-charts
description: >
Ship TanStack Charts with meaningful accessibility, deterministic SSR and
hydration, correct adapter lifecycle, renderer and export choices, exact
package subpaths, and explicit React Native validation.
metadata:
type: lifecycle
library: '@tanstack/charts'
library_version: '0.9.0'
sources:
- 'TanStack/charts:docs/guides/accessibility.md'
- 'TanStack/charts:docs/guides/ssr-and-hydration.md'
- 'TanStack/charts:docs/guides/exporting.md'
- 'TanStack/charts:docs/framework/*/adapter.md'
- 'TanStack/charts:packages/react-native-charts/README.md'
# Ship Accessible Charts
Run **trigger → inspect → decide → build → verify** before release. A chart is shipped only when its semantic alternative, adapter lifecycle, SSR policy, renderer, exports, package boundaries, and teardown are proven in a consumer-shaped scenario.
## Accessibility Checks
### Check: the name identifies the comparison
Expected:
```ts
const hostOptions = {
definition,
height: 320,
initialWidth: 640,
ariaLabel: 'Weekly downloads for Core and React packages',
ariaDescription: 'Values are seven-day totals. Missing weeks appear as gaps.',
}
```
Fail condition: the label says only “chart”, repeats a visible heading without the metric, or omits the comparison and period.
Fix: name the metric, compared entities, and time scope; put conclusions and detailed values in normal application content.
### Check: critical values have an equivalent representation
Expected: a visible heading and units, plus an adjacent summary or semantic table when precise values or application decisions depend on the chart.
Fail condition: the only way to retrieve an essential value is pointer hover, color, motion, or visual estimation.
Fix: bind the same semantic rows or selected key to application text/table controls.
### Check: every interaction has a non-pointer path
Expected: native point keyboard navigation, semantic buttons/inputs for free cursors and range controls, visible focus, cancel/reset paths, and meaningful committed-state text.
Fail condition: a transparent pointer overlay is the sole control surface.
Fix: use first-party controls where their keyboard contract fits and application-owned semantic controls otherwise.
## Lifecycle Checks
### Check: SSR uses a supported adapter and deterministic inputs
Expected:
```ts
import {
createChartRuntime,
defineChart,
lineY,
renderChartSvg,
} from '@tanstack/charts'
import { scaleLinear } from '@tanstack/charts/scales/linear'
import { scaleUtc } from 'd3-scale'
interface TrafficRow {
date: Date
visits: number
}
const rows: readonly TrafficRow[] = [
{ date: new Date('2026-08-10T00:00:00Z'), visits: 820 },
{ date: new Date('2026-08-11T00:00:00Z'), visits: 910 },
]
const definition = defineChart({
marks: [lineY(rows, { x: 'date', y: 'visits' })],
x: { scale: scaleUtc },
y: { scale: scaleLinear },
})
const runtime = createChartRuntime<TrafficRow, Date, number>()
const scene = runtime.render(definition, { width: 720, height: 400 })
export const svg = renderChartSvg(scene, {
ariaLabel: 'Daily traffic',
idPrefix: 'daily-traffic',
})
runtime.destroy()
```
Fail condition: definition construction reads browser layout, random values, local time, or unresolved async data; or the selected adapter does not promise SSR.
Fix: resolve data before render, use deterministic formatting and dimensions, and follow the selected adapter reference.
### Check: mount, update, and cleanup stay adapter-owned
Expected: one runtime per mounted adapter instance, complete immutable option updates, stable definitions until captured values change, and cleanup on unmount/disconnect.
Fail condition: application code calls DOM measurement or mounts a browser host during server render, or retains observers/listeners after removal.
Fix: use the adapter lifecycle or `mountChart` only in a browser-owned mount phase and call `destroy()` at teardown.
## Renderer and Export Checks
### Check: renderer choice matches the task
- SVG: visible server geometry, vector export, DOM styling, ordinary interactive charts.
- Canvas: high scene counts or raster-first output; server emits an accessible shell, not pixels.
- Static SVG: deterministic server/export artifact without browser interaction.
- React Native SVG: explicit native target with device-level validation.
### Check: export is reproducible
Expected: explicit dimensions, theme/background, scoped IDs, portable fonts/assets, intentional focus inclusion, and a meaningful exported name/description.
Fail condition: export depends on current responsive pixels or unreachable application CSS/resources.
Fix: render an explicit scene or serialize/rasterize with explicit artifact policy.
## Common Mistakes
### CRITICAL Using a generic accessible label
Wrong: `ariaLabel: 'Chart'`.
Correct: identify the metric, entities, period, and unit needed to understand the figure.
A generic label exposes a focusable graphic without useful identity.
Source: `docs/guides/accessibility.md`
### HIGH Making the chart the only representation
Wrong: require hover or visual estimation for exact operational values.
Correct: render a summary, table, or application controls from the same semantic data/state.
The chart surface is supplemental when exact values are critical.
Source: `docs/guides/accessibility.md`; archived responsive/accessibility notes
### CRITICAL Mounting a browser host during server rendering
Wrong: call `mountChart` or adapter DOM mount from a server lifecycle.
Correct: prerender a deterministic scene through a supported SSR adapter or `renderChartSvg`, then mount the browser host only after a real element exists.
Measurement and mutation require browser elements. Older Angular workarounds were especially prone to this boundary error.
Source: GitHub issue 56; `docs/guides/ssr-and-hydration.md`
### HIGH Putting behavior on adapter props
Wrong:
```tsx
<Chart definition={chart} tooltip keyboard />
```
Correct:
```tsx
const interactive = defineChart(chart, { tooltip, keyboard: true })
<Chart definition={interactive} ariaLabel="Revenue by month" />
```
Focus, tooltip, keyboard, controls, cursors, and SVG animation belong to the reusable definition; adapters own surface lifecycle and framework body composition. The current definition API replaces legacy adapter behavior props.
Source: chart-behavior migration in `CHANGELOG.md`; React chart reference
### HIGH Importing the universal barrel on native
Wrong: use `@tanstack/charts/universal` for every native chart.
Correct: use exact core mark/scale/scene and `@tanstack/charts/react-native` subpaths unless cross-platform authoring justifies the universal bundle.
Exact imports protect Metro and native declaration environments from unrelated browser and optional capability code.
Source: `API-FRICTION.md` F-154, F-171, F-173, F-256; React Native package README
### HIGH Tension: rich interaction versus portable rendering
DOM convenience can break static SVG, Canvas, native, SSR, or keyboard equivalence. Keep semantics in definitions and application state; use platform-specific body/host extensions only at the presentation seam.
See also: `build-chart-interactions/SKILL.md` and `extend-tanstack-charts/SKILL.md`
## Pre-Deploy Summary
- [ ] Meaningful name and concise description.
- [ ] Visible units, time range, and source context.
- [ ] Exact-value summary/table where required.
- [ ] Pointer, keyboard, touch, and cancel/reset scenarios.
- [ ] Reduced-motion and non-color evidence.
- [ ] Supported SSR policy with deterministic initial geometry.
- [ ] Stable definition, mark, datum, and resource IDs.
- [ ] Mount, update, resize, font relayout, and destroy verified.
- [ ] Renderer and export behavior verified from a packed consumer.
- [ ] Native claims verified on target devices when applicable.
## References
- [React](references/react.md)
- [Preact](references/preact.md)
- [Vue](references/vue.md)
- [Solid](references/solid.md)
- [Svelte](references/svelte.md)
- [Angular](references/angular.md)
- [Lit](references/lit.md)
- [Alpine](references/alpine.md)
- [Octane](references/octane.md)
- [React Native](references/react-native.md)
- [Renderers and export](references/renderers-and-export.md)
See also: `debug-and-verify-charts/SKILL.md` — SSR, accessibility, renderer, and package claims need consumer-level evidence.