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.
Server requirements
Section titled “Server requirements”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.
Render an SVG on the server
Section titled “Render an SVG on the server”This complete Node.js example creates a chart and saves it as revenue.svg:
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:
| Property | Contents |
|---|---|
svg | The serialized SVG, ready to save or insert into HTML. |
model | The accepted chart model and dataset, suitable for transfer to browser hydration. |
width, height | The 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.
Return SVG or include it in HTML
Section titled “Return SVG or include it in HTML”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.
Build-time rendering and request-time SSR
Section titled “Build-time rendering and request-time SSR”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.
Live server-rendered example
Section titled “Live server-rendered example”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.
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.
API and rendering contracts
Section titled “API and rendering contracts”| API | Purpose |
|---|---|
renderChartToSVG(options) from @revolist/charts/server | Render rows and mappings, a dataset, or a saved model to a serializable SVG result. |
hydrateChart(options) from @revolist/charts | Adopt 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
widthandheight, 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 uniqueidPrefixfor 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
createChartcalls 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.
Hydrate in the browser when needed
Section titled “Hydrate in the browser when needed”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('&', '&') .replaceAll('"', '"') .replaceAll('<', '<') .replaceAll('>', '>');
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.
Framework wrappers and Next.js
Section titled “Framework wrappers and Next.js”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.