| title | SSR and Hydration |
|---|---|
| description | Render deterministic chart markup on the server, preserve runtime work through hydration, and handle responsive dimensions without mismatches. |
TanStack Charts builds a platform-neutral scene before the selected renderer produces output. React, Preact, Vue, Solid, Svelte, and Octane use the same runtime and renderer on the server and in the browser.
| Adapter | Server output | Browser contract |
|---|---|---|
| React | Complete SVG; Canvas shell | Hydrates and adopts the existing surface |
| Preact | Complete SVG | Hydrates before the shared host mounts |
| Vue | Complete SVG | Hydrates before the shared host mounts |
| Solid | Complete SVG | Hydrates before the shared host mounts |
| Svelte | Complete SVG | Hydrates before the shared host mounts |
| Octane | Complete SVG; Canvas shell | Hydrates and adopts the existing surface |
| Angular | Not yet a verified adapter contract | Browser mount, immutable update, and teardown |
| Lit | Not yet a verified adapter contract | Browser registration, update, disconnect, reconnect |
| Alpine | None | Browser-only directive |
For adapters with server output, the browser must render the same definition, dimensions, formatters, and component tree. Angular and Lit may run inside applications with their own server infrastructure, but this library does not yet promise or test adapter hydration for them.
The server cannot measure a container. Supply one of these policies:
widthandheightfor a fixed-size chart;widthandaspectRatiofor a fixed-width proportional chart;initialWidthandheightfor a responsive chart;initialWidthandaspectRatiowhen height should follow width.
<Chart
definition={trafficChart}
ariaLabel="Daily traffic"
initialWidth={720}
aspectRatio={16 / 9}
/>The adapter uses an explicit width before initialWidth when deriving the
server height. After mounting, a responsive host observes the container and
renders at its measured width. Pick an initialWidth close to the layout's
common size to minimize the first responsive adjustment.
See Responsive Charts for the complete size policy.
Server and first-client output must agree for the same definition, size, and options. In particular:
- keep fixed definitions at module scope and recreate captured-data definitions from the same resolved data;
- sort unordered collections before creating marks;
- do not read
window, layout, time, locale, or random values while building a definition; - pass locale-sensitive formatters explicitly;
- rely on inferred IDs or unique positions, and supply explicit keys when the data has no stable identity;
- provide
idPrefixwhen multiple render roots need coordinated resource IDs.
Responsive chart functions are synchronous. Fetch and transform data in the application's server/data layer, then capture the resolved data in the definition.
Server and browser executions create separate runtime instances. Within the browser adapter's own initial render and layout-effect mount, the DOM host receives the already created browser runtime.
Do not conditionally replace a chart with a different component only because the code is executing on the server. That creates a different tree and gives up the shared render path.
@tanstack/charts/react/canvas and @tanstack/charts/octane/canvas render a
deterministic accessible shell on the server: a named chart root and five
aria-hidden canvas elements with the initial scene dimensions. The hidden
stable base bitmap preserves the raw canvas surface, while four live layers
model background, focus underlay, ordinary scene, and focus overlay paint. No
server Canvas API or pixel painting is required.
The client renders the same shell, adopts its existing root and canvases, sizes their backing stores for the device-pixel ratio, paints the scene, and attaches the shared interaction host. The first image appears after client mount; use the default SVG adapter when visible server-rendered geometry is required.
Automatic guide margins depend on text metrics. The server uses deterministic
fallback measurement unless you provide measureText. The browser host
remeasures when fonts become available and schedules a new layout.
ChartTextMeasurer is deliberately synchronous. Its options include the
resolved family, style, stretch, letter spacing, direction, locale, and font
scale so server and native implementations can use the same typography
contract. Hosts own asynchronous font readiness and request another render
after their available metrics change.
For strict pixel parity:
- Use a font available in both environments.
- Supply a deterministic
ChartTextMeasurer. - Supply the same
ChartTextTypography, including locale and font scale, in both environments.
Most applications should allow the browser's post-font layout correction instead of shipping a font engine to the server.
createChartRuntime and renderChartSvg form the server boundary:
import { createChartRuntime, renderChartSvg } from '@tanstack/charts'
const runtime = createChartRuntime<TrafficRow, Date, number>()
const scene = runtime.render(definition, { width: 720, height: 400 })
const svg = renderChartSvg(scene, {
ariaLabel: 'Daily traffic',
idPrefix: 'traffic',
})
runtime.destroy()renderChartSvg returns a string and does not require a DOM. A custom
ChartRenderer.prerender may produce another deterministic shell. Browser-only
focus, tooltip, reconciliation or paint, animation, and export begin when its
surface mounts.
- Server data is fully resolved before chart rendering.
- Initial dimensions are explicit and representative.
- Definition, transformed data, and formatting are deterministic.
- Keys and
idPrefixare stable. - The same adapter and definition render on both sides.
- Browser-only work lives in host callbacks or application effects.
- Font-driven relayout is expected or a text measurer is supplied.
See the selected framework adapter page and Runtime and Scene for the exact contracts.