Server side rendering
ApexCharts fully supports server-side rendering for Next.js, Nuxt, SvelteKit, Astro, and other modern meta-frameworks. Charts rendered on the server produce static SVG that is immediately visible to users and web crawlers, with full interactivity restored on the client via hydration.
Package Entry Points
Two dedicated entry points cover the SSR workflow:
| Import | Environment | What it provides |
|---|---|---|
apexcharts/ssr | Node.js / server | renderToString(), renderToHTML() |
apexcharts/client | Browser | hydrate(), hydrateAll(), isHydrated() |
apexcharts | Browser (full) | Standard full bundle, no SSR methods |
Server-Side Rendering
Use renderToHTML() to generate hydration-ready HTML. It embeds the chart configuration in the output so the client can fully restore interactivity without re-fetching data.
// server.js (Node.js / any SSR framework)
import ApexCharts from 'apexcharts/ssr'
const html = await ApexCharts.renderToHTML(
{
series: [{ name: 'Sales', data: [30, 40, 35, 50, 49, 60, 70] }],
chart: { type: 'bar' },
xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] }
},
{ width: 600, height: 350 }
)
// html is a self-contained string ready to embed in your page:
// <div class="apexcharts-ssr-wrapper" data-apexcharts-hydrate
// data-apexcharts-config="...">
// <svg ...>...</svg>
// </div>
renderToHTML() Options
| Option | Type | Default | Description |
|---|---|---|---|
width | number | 400 | Chart width in pixels |
height | number | 300 | Chart height in pixels |
scale | number | 1 | SVG scale factor (useful for high-DPI output) |
className | string | '' | Additional CSS class added to the wrapper div |
renderToString() — SVG Only
Use renderToString() when you only need the raw SVG string, for example to save to a file, pipe to a PDF renderer, or embed inside your own wrapper element.
import ApexCharts from 'apexcharts/ssr'
const svg = await ApexCharts.renderToString(
{
series: [{ data: [10, 41, 35, 51, 49, 62, 69, 91, 148] }],
chart: { type: 'line' }
},
{ width: 800, height: 400 }
)
// svg is a plain SVG string
// '<svg xmlns="http://www.w3.org/2000/svg" ...>...</svg>'
Client-Side Hydration
Once the server-rendered HTML is in the browser, call hydrate() or hydrateAll() to restore full interactivity — tooltips, zoom, pan, legend toggling, and all other interactions.
// client.js (browser only)
import ApexCharts from 'apexcharts/client'
// Hydrate a single chart
const el = document.getElementById('my-chart')
const chart = ApexCharts.hydrate(el)
// Or hydrate every chart on the page at once
const charts = ApexCharts.hydrateAll()
Hydrate All on DOM Ready
import ApexCharts from 'apexcharts/client'
document.addEventListener('DOMContentLoaded', () => {
ApexCharts.hydrateAll()
})
hydrateAll() with a Custom Selector
By default hydrateAll() targets every element with data-apexcharts-hydrate. Pass a CSS selector to restrict hydration to a subset of elements.
// Only hydrate charts inside the dashboard section
ApexCharts.hydrateAll('#dashboard [data-apexcharts-hydrate]')
Applying Client-Side Overrides on Hydration
Pass a clientOptions object as the second argument to override parts of the SSR configuration when hydrating. Common uses: re-enabling animations, adding event handlers, or changing theme for the interactive version.
import ApexCharts from 'apexcharts/client'
ApexCharts.hydrateAll('[data-apexcharts-hydrate]', {
chart: {
animations: { enabled: true, speed: 400 }
},
theme: { mode: 'dark' }
})
Animations are automatically re-enabled on hydration unless you explicitly set animations.enabled: false in clientOptions.
Checking Hydration State
import ApexCharts from 'apexcharts/client'
const el = document.getElementById('my-chart')
if (ApexCharts.isHydrated(el)) {
console.log('Chart is already interactive')
} else {
ApexCharts.hydrate(el)
}
Hydration Events
Each element dispatches an apexcharts:hydrated custom event when hydration completes successfully. Listen to it if you need to run code after the chart is interactive.
const el = document.getElementById('my-chart')
el.addEventListener('apexcharts:hydrated', (e) => {
const { chart } = e.detail // the ApexCharts instance
console.log('Chart ready:', chart)
})
ApexCharts.hydrate(el)
Next.js Example
// app/page.jsx (Server Component)
import ApexCharts from 'apexcharts/ssr'
export default async function Page() {
const chartHTML = await ApexCharts.renderToHTML(
{
series: [{ name: 'Monthly Revenue', data: [31, 40, 28, 51, 42, 109, 100] }],
chart: { type: 'area' },
xaxis: { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'] }
},
{ width: 700, height: 350 }
)
return (
<main>
<h1>Dashboard</h1>
<div dangerouslySetInnerHTML={{ __html: chartHTML }} />
<ClientHydrator />
</main>
)
}
// app/ClientHydrator.jsx ('use client')
'use client'
import { useEffect } from 'react'
import ApexCharts from 'apexcharts/client'
export default function ClientHydrator() {
useEffect(() => {
ApexCharts.hydrateAll()
}, [])
return null
}
Nuxt Example
// server/api/chart.js
import ApexCharts from 'apexcharts/ssr'
export default defineEventHandler(async () => {
const html = await ApexCharts.renderToHTML(
{
series: [{ data: [10, 41, 35, 51, 49, 62, 69] }],
chart: { type: 'line' }
},
{ width: 600, height: 300 }
)
return { html }
})
<!-- pages/index.vue -->
<template>
<div v-html="chartHtml" />
</template>
<script setup>
import ApexCharts from 'apexcharts/client'
const { data } = await useFetch('/api/chart')
const chartHtml = data.value.html
onMounted(() => {
ApexCharts.hydrateAll()
})
</script>
How the HTML Output Is Structured
renderToHTML() returns a wrapper div containing the static SVG and a base64-encoded copy of the chart configuration. The client uses the encoded config to reconstruct the fully interactive chart on hydration — no server round-trip needed.
<div class="apexcharts-ssr-wrapper"
data-apexcharts-hydrate
data-apexcharts-config="eyJzZXJpZXMiOi4uLn0=">
<svg xmlns="http://www.w3.org/2000/svg" ...>
<!-- full chart SVG -->
</svg>
</div>
After hydration, the element receives data-apexcharts-hydrated="true" and the data-apexcharts-config attribute is removed.