Animations
ApexCharts provides a smooth experience with the help of SVG.js's built-in animations. Select a chart type and click Update to see the animation in action.
To see all options available in animations, please refer to Animations configuration.
Reduced Motion
ApexCharts skips animations entirely when the operating system asks for reduced motion. This is deliberate and on by default since 5.12, and it is what WCAG 2.3.3 asks of any interface that moves on its own.
While (prefers-reduced-motion: reduce) matches, chart.animations.respectReducedMotion forces both of these off for as long as the preference is on:
chart.animations.enabled, the initial mount drawchart.animations.dynamicAnimation.enabled, the data-update transitions
Because both go, the symptom is "nothing animates at all" rather than "animations look different". The chart still renders in full and every value is correct. It simply arrives in its final state on the first frame, which is why a live demo can look frozen.
Charts running 5.11 or earlier ignore the preference entirely and animate regardless.
Am I in reduced motion?
matchMedia('(prefers-reduced-motion: reduce)').matches
true means the preference is on, and a chart that renders without animating is correct behaviour rather than a bug.
Where the preference comes from
| Source | Where it lives |
|---|---|
| macOS | System Settings > Accessibility > Display > Reduce motion |
| Windows 11 | Settings > Accessibility > Visual effects > Animation effects |
| Windows Battery Saver | Forces the preference on automatically while it is active |
| Remote desktop and VDI | Most sessions report it whether or not anyone chose it |
The last two matter most for diagnosis, because they turn the preference on without anyone asking for it. That is how a developer ends up with charts that never animate on their desktop while the same page animates normally on their phone.
Opting out
The default is the right one for most sites, so treat this as a decision rather than a fix. A kiosk display, a screen-recording rig or a QA harness is a fair reason to animate anyway:
chart: {
animations: {
respectReducedMotion: false,
},
}
From 7.6.0 this covers the whole chart. The animations tweened in JavaScript come back (the initial mount draw, the gradual reveal, data-update transitions and chart-type morph), and so do the ones driven by CSS: the pie and donut slice-offset slide, the drilldown loading spinner, the tooltip and crosshair fades, and the data-label fade on a collapsing series. Internally the option puts an apexcharts-ignore-reduced-motion class on the chart's canvas, which is what the stylesheet's reduced-motion rules are scoped against.
On 7.5.1 and earlier the flag reached only the JavaScript. The stylesheet carried its own unconditional @media (prefers-reduced-motion: reduce) block flattening every duration inside .apexcharts-canvas with !important, and no JavaScript flag can reach a CSS rule, so the CSS-driven transitions above stayed instant however the option was set. Upgrading is the fix. Overriding it from a page means out-specifying an !important rule on every element that moves, which is fragile and easy to get half right.
Custom Easing (Cadence)
The animations.easing option accepts a named curve, a cubic-bezier array, or a function, so you can tune how the generic tweens feel without touching anything else:
const options = {
chart: { animations: { easing: 'easeOutBack' } }, // or [0.34, 1.56, 0.64, 1], or (t) => t * t
}
Register your own named curve with ApexCharts.registerEasing('bounce', (t) => /* ... */). The default (easeInOutSine) is unchanged, so existing charts animate exactly as before, and the tuned initial-draw easings (pen-stroke, grow, pop) stay fixed. A separate data-change override is available via dynamicAnimation.easing; see chart.animations.
Pick a curve, then Shuffle data to watch the bars tween to their new heights with it. Set it via chart.animations.easing: a registered name, a cubic-bezier array, or a function. The default, easeInOutSine, leaves existing charts animating exactly as before.
Morphing Between Chart Types
When updateOptions changes chart.type, ApexCharts can tween from the old shape to the new one instead of destroying and rebuilding the chart. The morph is an optional, tree-shakeable feature, so it must be imported before it takes effect:
import ApexCharts from 'apexcharts'
import 'apexcharts/features/morph'
Then enable it under chart.animations:
chart: {
animations: {
chartTypeMorph: {
enabled: true,
speed: 600,
},
},
}
Supported transitions include bar ↔ pie / donut / radialBar / polarArea / funnel / pyramid / gauge, plus the trivial pie ↔ donut ↔ polarArea cases. When the source and target types (or their data shapes) are incompatible, the chart falls back to an instant snap.
Switch types to watch supported pairs tween between shapes. Enable it with the tree-shakeable apexcharts/features/morph import and chart.animations.chartTypeMorph. Incompatible pairs fall back to an instant snap.
Conserving the Ink
A morph between one mark and many objects, a bar becoming the dots it was counting, does not crossfade. Frame by frame a crossfade is a double exposure: two pictures both half-visible, neither becoming the other, which is why easing never made it read as one shape turning into another.
Instead the mark is cut into exactly as many cells as there are objects, and every cell flies to its own object, corners rounding off and fill blending on the way. A summary mark is cut along its own silhouette rather than its bounding box, and a wedge along its curve, which is how a donut's hole survives being taken apart.
This is what rowSeries() is for: it hands back the rows a mark stands for, so switching type opens the summary into its own observations rather than swapping in an unrelated chart.
chart.updateOptions({
chart: { type: 'unit' },
series: chart.rowSeries()
})
Any two mark families pair. The engine used to decline combinations simply because nobody had exercised them. The only pairing still closed is a dot cluster against a partition, where a divider has no cut for a tile or an arc and the result would fall back to a fade. Treemap and sunburst pair at every level rather than only the leaves, and a box plot unfolds into its violin and folds back.