Skip to content

Server-side rendering (SSR)

Render Charts to SVG directly on a Node.js server with renderChartToSVG from @revolist/charts/server. Use the output in an HTTP response, a server-rendered page, a generated report or a saved SVG file. The server produces the chart’s marks, labels and accessible description before any browser JavaScript runs.

Server rendering is complete without a browser or UI framework. The SVG remains readable with JavaScript disabled. Start with the server example below; optional browser hydration is covered later for charts that also need interactions.

Follow Installation for licensed access to @revolist/charts. The server renderer’s happy-dom dependency is installed automatically with Charts; no additional package installation is needed.

The server entry is ESM and requires Node.js supported by Happy DOM 20 (Node.js 20 or later). Every render uses an isolated, non-executing DOM; you do not need to install global window or document objects. Browser imports do not load Happy DOM. This entry does not support Edge runtimes.

This complete Node.js example creates a chart and saves it as revenue.svg:

render-chart.mjs
import { writeFile } from 'node:fs/promises';
import { renderChartToSVG } from '@revolist/charts/server';
const result = await renderChartToSVG({
chartId: 'monthly-revenue',
chartType: 'line',
width: 800,
height: 400,
theme: 'light',
data: [
{ month: 'Jan', revenue: 120 },
{ month: 'Feb', revenue: 180 },
{ month: 'Mar', revenue: 160 },
],
mapping: {
category: { field: 'month' },
series: [{ field: 'revenue', label: 'Revenue' }],
},
presentation: { title: 'Monthly revenue' },
});
await writeFile('revenue.svg', result.svg, 'utf8');

Run it with node render-chart.mjs. The result contains:

PropertyContents
svgThe serialized SVG, ready to save or insert into HTML.
modelThe accepted chart model and dataset, suitable for transfer to browser hydration.
width, heightThe actual SVG layout dimensions.

You can also supply a dataset or a saved model instead of rows and mappings. Fetch and authorize data before calling the renderer; server fetch functions and credentials stay in your application.

To serve the chart directly from a route using the standard Response API:

// In your server route, after obtaining result from renderChartToSVG:
return new Response(result.svg, {
headers: { 'Content-Type': 'image/svg+xml; charset=utf-8' },
});

For a server-rendered page, insert result.svg inside a sized host:

// Server: include this markup in your HTML response.
const chartHTML = `
<div id="revenue-chart" style="width:100%;height:${result.height}px">
${result.svg}
</div>
`;

This is a complete server-rendered chart. No model transfer or browser script is required. Insert only trusted renderer output as HTML, and include only data the visitor may read.

The rendering API works in either lifecycle:

  • Build time: render known data while generating a static site or report, and save the SVG or include it in generated HTML.
  • Request time: load the authorized dataset in an HTTP handler or framework server loader, render the chart, and include its output in that response.

Both produce usable SVG before browser JavaScript runs. Hydration adds interactions to either output; it is independent of when the SVG was generated. In an SSR bundler, keep the Node-only happy-dom dependency external to the server bundle. Next.js configuration is described in the framework section below.

This chart follows the same server-render → HTML → optional hydration flow. Disable JavaScript and reload to inspect the static SVG. With JavaScript enabled, focus a point or choose Show forecast to update it with illustrative values.

Monthly revenueIllustrative data · € thousands050100150200250300€ thousandsJan · Revenue: 120Feb · Revenue: 180Mar · Revenue: 160Apr · Revenue: 240May · Revenue: 210Jun · Revenue: 2906 finite source observations across 1 measures; 6 observations displayed across 1 measures.JanFebMarAprMayJunMonthly revenue. line chart. 6 categories, 1 measures, 6 numeric values. 6 observation targets and 0 aggregate inspection targets. Use Tab to enter or leave chart inspection. Use arrow keys, Home, and End to navigate displayed targets. Enter or Space activates observations. Aggregate targets are for inspection only.
SVG rendered on the server. JavaScript adds interactions.

The status identifies when browser hydration finishes; Show forecast stays disabled until then. View the document’s network response or page source to find <svg data-chart-ssr="1"> before browser scripts run. Hydration consumes that marker. The example uses the same server-rendering and browser hydration APIs shown above.

APIPurpose
renderChartToSVG(options) from @revolist/charts/serverRender rows and mappings, a dataset, or a saved model to a serializable SVG result.
hydrateChart(options) from @revolist/chartsAdopt the initial SVG in options.container and return the normal ChartRef.
chart.update(patch)Update the hydrated chart. Rendering the server snapshot again is unnecessary.
chart.destroy()Remove owned SVG, controls and listeners when the application removes the host.
  • Supply finite positive width and height, at most 32768. The native layout keeps its existing minimum of 320 × 240 and rounds to pixels; returned dimensions describe the actual SVG. Keep the host sized to avoid layout shifts.
  • Set a unique chartId, or a unique idPrefix for repeated copies of a saved model. Generated IDs and fragment references are deterministic and scoped.
  • Use the same initial model, locale, renderer customization, theme and dimensions in the browser to retain corresponding datum nodes. Later resize or font measurement can refine layout. theme: 'auto' resolves light on the server; choose an explicit theme for predictable initial output.
  • Leave the hydration markers intact. A host must contain one matching server SVG. Call hydration once, then use the returned ref; normal createChart calls continue to mount fresh SVG by default.
  • Fetch data before server rendering. Runtime dataSource, custom renderers, containers and abort signals are not accepted by the server API. Hydration accepts browser callbacks and an abort signal, as shown above.
  • This API covers the 68 native chart types. Optional provider-backed geographic charts, ECharts Canvas, and browser image/raster export are outside its scope.
  • Insert only trusted renderer output as HTML. Transfer plain JSON through an escaped HTML attribute or your framework’s serializer, rather than inserting unescaped JSON into an executable script. Do not pass arbitrary visitor-authored SVG as output.

Add hydration only when the server-rendered chart needs browser interactions. Transfer result.model alongside the SVG using your framework’s serializer or an escaped HTML attribute. For a plain server HTML template:

// Server: escape JSON for a double-quoted HTML attribute.
const modelAttribute = JSON.stringify(result.model)
.replaceAll('&', '&amp;')
.replaceAll('"', '&quot;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;');
const chartHTML = `
<div id="revenue-chart"
style="width:100%;height:${result.height}px"
data-chart-model="${modelAttribute}">${result.svg}</div>
`;

The transferred model is visible to the visitor. Keep credentials and server fetch functions on the server. Then run this code in your application’s browser bundle after the host exists:

// Browser entry, bundled by your application.
import { hydrateChart } from '@revolist/charts';
const container = document.querySelector<HTMLElement>('#revenue-chart')!;
const controller = new AbortController();
const chart = await hydrateChart({
container,
model: JSON.parse(container.dataset.chartModel!),
signal: controller.signal,
onNodeClick(detail) { console.log(detail); },
});
// Later, update the existing chart through its normal API.
await chart.update({ presentation: { title: 'Updated revenue' } });
// Call from your application's unmount/navigation cleanup.
export function disposeChart() {
controller.abort();
chart.destroy();
}

Hydration adopts the existing SVG and reuses matching nodes while rebuilding chart state, controls and listeners. Keep the hydration markers in the SVG and use the same initial model, theme, locale and renderer customization. Call hydration once per host, then use the returned ChartRef for updates and cleanup.

React, Vue and Svelte wrappers accept the optional serverRender result along with options={{ model: result.model }} (or the framework’s equivalent binding). They include initial SVG and hydrate it after mounting. Without serverRender, their existing empty-host server output remains unchanged. The Angular wrapper retains its existing browser-mount lifecycle.

The React package declares 'use client', so a Next.js Server Component can import RevoChart directly. Render the snapshot through @revolist/charts/server in a Node.js route, keep happy-dom in serverExternalPackages, and pass the serializable result as serverRender. Define event callbacks and formatter functions inside a Client Component. See Framework components for the component props; the package’s docs/server-rendering.md includes a complete Next.js App Router example.