Skip to content

Using amCharts 5 with SvelteKit

Use amCharts 5 in Svelte and SvelteKit with our @amcharts/amcharts5-svelte package. It creates and disposes the chart with the element, and works with server rendering.

Create a project, if you do not have one, and install amCharts with the package:

Terminal window
npx sv create my-app
cd my-app
npm install @amcharts/amcharts5 @amcharts/amcharts5-svelte

It needs Svelte 4 or later and amCharts 5.21.4 or later.

SvelteKit’s dev server leaves amCharts to Node, which cannot load its files on its own. Add it to the server build in vite.config.ts. The production build does not need it:

import adapter from "@sveltejs/adapter-node";
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [sveltekit({ adapter: adapter() })],
ssr: {
noExternal: ["@amcharts/amcharts5"]
}
});

In Svelte 5.29 or later, use attachments. attachAmChart() gives your function a new root in the element; build the chart in it as in any amCharts example. attachAmChartConfig() builds a chart from a JSON config in the library’s <am5-chart> element. Both elements need a height.

<script lang="ts">
import { attachAmChart, attachAmChartConfig } from "@amcharts/amcharts5-svelte";
import type { Root } from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
let { data, config } = $props();
// The series, to give it new data later
let series = $state.raw<am5xy.ColumnSeries>();
function buildChart(root: Root) {
root.setThemes([am5themes_Animated.new(root)]);
const chart = root.container.children.push(am5xy.XYChart.new(root, {}));
const xAxis = chart.xAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "category",
renderer: am5xy.AxisRendererX.new(root, {})
}));
const yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
}));
series = chart.series.push(am5xy.ColumnSeries.new(root, {
xAxis: xAxis,
yAxis: yAxis,
categoryXField: "category",
valueYField: "value"
}));
}
// The data goes to the chart once it is made, and again when it changes,
// without making the chart again
$effect(() => {
if (series) {
const rows = $state.snapshot(data);
series.get("xAxis").data.setAll(rows);
series.data.setAll(rows);
}
});
</script>
<div {@attach attachAmChart(buildChart)} style="height: 500px"></div>
<am5-chart {@attach attachAmChartConfig({ config, themes: [am5themes_Animated] })} style="height: 500px"></am5-chart>
  • The chart is made when the element is there, and disposed when it goes. Like any attachment, it is made again when state read in its expression changes.
  • attachAmChart(buildChart, { renderer: "svg" }) draws the chart as SVG.
  • A theme with settings is a pair: themes: [am5themes_Animated, [am5themes_Adaptive, { baseColor: "#4150a0" }]].
  • attachAmChart(buildChart, { onError }) gets errors from your function. Without it, they are reported as uncaught errors.
  • Give amCharts plain data: $state.snapshot() turns Svelte state into it.
  • The <am5-chart> element dispatches ready (event.detail has root and chart) and error: listen with onready and onerror.

A map’s config names its geodata ("geoJSON": "am5geodata_worldLow"), and a config may name a locale ("locale": "am5locales_de_DE"), instead of carrying them. With npm imports they are not globals: import the files the config names and give them in resources, under the same names:

<script>
import am5geodata_worldLow from "@amcharts/amcharts5-geodata/worldLow";
</script>
<am5-chart {@attach attachAmChartConfig({ config: mapConfig, resources: { am5geodata_worldLow } })} style="height: 400px"></am5-chart>

Use the actions instead. With deps, the chart is made again when a value in it changes, compared by content:

<div use:amChart={{ setup: buildChart, deps: [data] }} style="height: 500px"></div>
<am5-chart use:amChartConfig={{ config }} on:ready={(event) => console.log(event.detail.chart)}></am5-chart>

With a commercial license, call am5.addLicense() once in src/hooks.client.ts, which runs when the app starts in the browser.

An example app is on GitHub.

» amCharts 5 with SvelteKit

To manage the chart yourself, create the root in onMount and dispose it in the function it returns. onMount runs in the browser only:

<script>
import { onMount } from "svelte";
import * as am5 from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
let chartdiv;
onMount(() => {
const root = am5.Root.new(chartdiv);
const chart = root.container.children.push(am5xy.XYChart.new(root, {}));
// ... axes, series and data
return () => {
root.dispose();
};
});
</script>
<div bind:this={chartdiv} style="height: 500px"></div>