Skip to content

Update dependency apexcharts to v6 - #334

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/apexcharts-6.x
Open

Update dependency apexcharts to v6#334
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/apexcharts-6.x

Conversation

@renovate

@renovate renovate Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
apexcharts (source) 3.41.06.7.0 age confidence

Release Notes

apexcharts/apexcharts.js (apexcharts)

v6.7.0: 💎 Version 6.7.0

Compare Source

The headline is a new chart type, sunburst: a hierarchical radial chart (a nested pie and donut) that draws tree-structured data as concentric rings, one ring per level of the hierarchy, with each child arc nested inside its parent's angular span. This release also brings rounded corners and inter-slice spacing to pie and donut slices, a parliament (hemicycle) layout for the unit chart, an optional hover tooltip on point annotations, and a broad reliability and security pass. Two behavior changes are worth reading before you upgrade: a legend click on pie, donut, and polarArea now toggles the slice in and out, and the premium features now require an entitled plan rather than just any valid key. Every existing config renders unchanged.

✨ New

The sunburst chart type

chart.type: 'sunburst' renders a hierarchy as a ring of nested arcs: the first level fills a donut around the centre hole, and each deeper level stacks outward, with every child arc constrained to the angle of its parent. It is a non-axis chart (dispatched like pie or treemap) and is tree-shakeable via import 'apexcharts/sunburst', so it adds nothing to the core bundle unless you use it. It is a free chart type, not gated.

Data is the familiar x / y shape with a children array for nesting:

new ApexCharts(el, {
  chart: { type: 'sunburst' },
  series: [{
    data: [
      { x: 'Mobile', y: 55, children: [
        { x: 'iOS', y: 30, children: [
          { x: 'iOS 17', y: 18 },
          { x: 'iOS 16', y: 9 },
        ]},
        { x: 'Android', y: 23 },
      ]},
      { x: 'Desktop', y: 33, children: [
        { x: 'Windows', y: 20 },
        { x: 'macOS', y: 10 },
      ]},
    ],
  }],
  plotOptions: {
    sunburst: { innerSize: '25%', borderRadius: 5, spacing: 1 },
  },
})

plotOptions.sunburst.innerSize sets the centre hole (percentage or pixels), borderRadius rounds the arc corners, and spacing opens a gap between neighbouring arcs. Colours, stroke, legend, and title behave as they do on pie and donut.

Rounded corners and spacing for pie and donut

plotOptions.pie.borderRadius rounds the corners of each slice, and plotOptions.pie.spacing opens a gap between slices, so a pie or donut can read as a set of separated, soft-cornered segments rather than a solid wheel. Both apply to polarArea as well.

A parliament layout for the unit chart

The unit chart (introduced in 6.6.0) gains a plotOptions.unit.arc layout: a parliament or hemicycle that arranges the marks as seats in concentric arced rows across an annulus, filled in category order. It is the natural shape for seat counts and any part-to-whole where a semicircle reads better than a grid. The gather animation is now tunable too, with configurable easing and enter motion.

Optional tooltips on point annotations

Point annotations can now show a hover tooltip, so an annotated marker can carry its own explanatory text without a separate custom element.

🐛 Fixes

  • A series missing its data no longer breaks the rest of the chart. A series object without a data property used to abort parsing of every series after it, leaving the parsed data out of step with the series names. It is now treated as an empty series, and the remaining series parse and stay aligned.
  • updateSeries and updateOptions no longer hang on a failed render. Their promises now reject when the render throws, instead of never settling, so await chart.updateSeries(...) can be caught rather than leaking a pending promise.
  • Combo charts label the right series. Goal lines and data labels on a mixed chart now use the real series index rather than the compacted subset index, so labels and goals no longer attach to the wrong series when some series are hidden.
  • Server-side rendering no longer crashes on image fills, and an out-of-range annotation yAxisIndex and a sunburst drilldown cycle are fixed.
  • Callbacks are safe after destroy(). Animation, resize, and pending timeout callbacks are guarded against firing on a destroyed chart, and the detached SVG root is released on teardown, closing a class of update-then-destroy errors and leaks.
  • CSV export guards against formula injection. Field values that begin with a formula character are neutralised so an exported CSV cannot execute when opened in a spreadsheet.
  • Fewer surprises from bad numbers. NaN and Infinity guards were added across polarArea, custom series, axis labels, tooltips, and gradients, so a stray non-finite value degrades gracefully instead of throwing.
  • Assorted interaction and lifecycle fixes, including a stuck zoom shift-latch and a duplicate mousewheel binding, a keyboard-navigation listener leak on updateOptions, annotation tooltips that could suppress the series tooltip chart-wide, an empty-candlestick crash, a redundant redraw on a resize that did not change the drawing box, and a per-render reset of the hasNullValues and invalidLogScale flags.

TypeScript

plotOptions.sunburst, plotOptions.pie.borderRadius / spacing, and the unit arc layout options are fully typed, and chart.type accepts 'sunburst'.

Compatibility

  • Legend click on pie, donut, and polarArea now toggles the slice in and out (it previously darkened and expanded the slice). If your app relied on the old click behavior, review this.
  • Premium features now require an entitled plan, not just any valid key. The premium modules (the unit chart type plus storyboard, link, ink, measure, contextMenu, perspectives, and history) clear the watermark only on a premium or enterprise plan. A valid pro key, or the free tier, keeps them in trial mode with the watermark and logs a one-time upgrade notice; it is not treated as an invalid key. Existing pro-plan customers using these features will now see the watermark. Everything else, every free chart type and module, is never gated.
  • No breaking API changes, and no renamed or removed options.

v6.6.1

Compare Source

v6.6.0: 💎 Version 6.6.0

Compare Source

The headline is a new premium chart type, unit: one mark per unit of value, drawn as dot clusters, pictograms, waffles, or beeswarms, with a keyed tween that re-forms the marks whenever the data, grouping, or filter changes. It ships with six layouts, per-mark data, and a waffle alias, and it is the first premium chart type (it renders in trial mode with a watermark until a key is set). This release also adds signature verification to the license manager and fixes a zoom-out edge case. Existing configs render unchanged.

✨ New

The unit chart type (premium)

chart.type: 'unit' renders a discrete mark for every unit of value instead of a single bar or slice, so "37 of 200" reads as a countable quantity. It is a non-axis chart (dispatched like pie or treemap) and is tree-shakeable via import 'apexcharts/unit'. On every update each mark tweens from its old position to its new one, so re-grouping, filtering, or a changing count re-forms the marks rather than redrawing from scratch.

new ApexCharts(el, {
  chart: { type: 'unit' },
  series: [276, 266, 3],
  labels: ['For', 'Against', 'Abstain'],
  plotOptions: { unit: { layout: 'grouped' } },
})

Six layouts via plotOptions.unit.layout:

  • grouped (default): one phyllotaxis blob per category, laid out in a row.
  • packed: one shared blob, coloured by group and sorted so the minority nests in the centre.
  • columns: each category is a vertical bar built from stacked dots (a waffle column).
  • grid: one waffle lattice, a part-to-whole square "pie" (grid.total rounds it to a fixed cell budget, e.g. 100 for a percentage waffle).
  • grid with split: true: small multiples, one mini-waffle per category over a faint track, in a trellis.
  • scatter: marks on real value axes, as a 1D beeswarm (laned by category, deterministic anti-overlap packing), a 2D value-value plot (scatter.y: 'value'), or area-scaled bubbles (scatter.sizeRange). The layout draws its own axes with a homegrown nice-number scale.

Also included:

  • Shapes: circle, square, and image (isotype pictogram, with image.tint to recolour a monochrome icon to its category colour).
  • Per-mark data: alongside flat counts, an object form series: [{ name, data: [{ value, x, z, name, fillColor, id }, ...] }] gives each mark its own colour, position, size, and tooltip content.
  • Transitions (transition): group (default, per-category), flow (the anonymous crowd migrates and recolours across a regroup, the circles-to-bars effect), and identity (a specific mark persists across any regroup or relayout, keyed by id / name).
  • Sizing: numeric or auto dot size, opt-in sizeByValue bubbles, unitValue waffle scaling (1 mark = N units), and a maxUnits safety cap.
  • Labels and chrome: per-cluster clusterLabels (a curved arc over a blob or a straight label above / below a bar, position: 'top' | 'bottom'), per-mark tooltips, legend click to hide and show a category with an animated re-flow, and the standard fill.opacity so overlapping bubbles read through each other.

Nine interactive demos ship under samples/*/unit and samples/*/waffle: a workforce dot cluster, a population age-slider, a pictogram population, a team roster, a life-expectancy beeswarm, a cost-of-living bubble scatter, a scrollytelling marathon storyboard, a startup-funding walkthrough, an electricity-mix waffle, and an urbanisation small-multiple waffle.

The waffle chart type

chart.type: 'waffle' is a thin alias of unit: it presets the grid layout with square cells, so a part-to-whole waffle is one line of config. With grid.total: 100 the values are largest-remainder rounded to exactly 100 cells, so the grid always reads as percentages. The original type is preserved on chart.requestedType, and an explicit layout or shape still wins.

new ApexCharts(el, {
  chart: { type: 'waffle' },
  series: [35, 23, 15, 9, 8, 6, 4],
  labels: ['Coal', 'Gas', 'Hydro', 'Nuclear', 'Wind', 'Solar', 'Other'],
  plotOptions: { unit: { grid: { columns: 10, total: 100 } } },
})

🐛 Fixes

  • Zoom-out never stalls on the last category. While zooming out, the high edge is now rounded up instead of down, so the visible span grows by at least one whole category per step rather than appearing stuck at the edge.

TypeScript

plotOptions.unit is fully typed across all layouts and their option groups (grid, scatter, clusterLabels, sizeByValue, image, columns, tooltip), and chart.type accepts 'unit' and 'waffle', with chart.requestedType carrying the original alias.

Compatibility

  • No breaking API changes, and no renamed or removed options.
  • unit (and its waffle alias) is the first premium chart type: it renders fully in trial mode with an APEXCHARTS watermark until a key is set. Every other chart type stays free and is never watermarked.
  • The unit chart is opt-in and additive; charts of every other type render unchanged.
  • New unit regression tests (packing determinism, layout geometry, keyed transitions, scatter axes and bubbles, waffle cell allocation, legend toggle, and premium gating) run alongside the existing interaction and end-to-end suites.

v6.5.0: 💎 Version 6.5.0

Compare Source

A release built around interaction polish and one new capability. Mouse-wheel zoom is now smooth and cursor-anchored, the brush/selection now lines up exactly with the bars underneath it, and a run of interaction fixes clears up crossfilter, heatmap updates, and group tooltips. It also introduces optional license enforcement for the premium features: they keep working without a key (trial mode), just with a watermark. No chart types are gated, and existing configs render unchanged.

✨ New

Licensing for the premium features (trial mode)

Seven premium modules now run under a lightweight, offline license check: storyboard, link (crossfilter / linked views), ink, measure, contextMenu, perspectives, and history. Without a valid key they still work fully in trial mode, but the chart shows an unobtrusive APEXCHARTS watermark; a valid key removes it. Everything else, every chart type and every free module, is never gated and stays silent.

ApexCharts.setLicense('APEX-...') // or per-chart via chart.license

A few things worth knowing:

  • In use, not bundled. Importing a premium module without actually enabling it does not watermark; only using it does.
  • Live. A late setLicense(validKey) followed by an update clears an on-screen watermark; no full re-render needed.
  • One key across the family. The key format is shared with the rest of the ApexCharts family (apexgantt, apextree, apexsankey, and friends), validated offline with no network call. SSR-safe.

⚡ Improvements

Continuous, cursor-anchored mouse-wheel zoom

Wheel and trackpad zoom used to run a fixed step at most once every 400ms and drop everything in between, which read as lag. It is now coalesced per animation frame and anchored to the cursor: the data point under the pointer stays put while the window scales around it, so a trackpad's stream of small deltas feels continuous. The zoomed event fires once per gesture, not once per wheel tick.

🐛 Fixes

  • The brush/selection now matches the bars underneath it. On numeric and datetime bar charts, brushed ranges drifted from the columns they visibly covered (the first column lit up too early, the last could never be fully selected). Each gesture had been computing its own pixel-to-data conversion, so fixing one path quietly desynced another. There is now a single source-of-truth mapping shared by bar placement and every selection gesture (new drag, dragging the rect, resize handles, and a preselected chart.selection.xaxis), so the reported range always equals the rectangle you see. Range-binned crossfilter histograms now span their outer bin edges too, so every bin, including both edges, is fully brushable, and a chart.link.bins: { width } option is no longer silently dropped.
  • Heatmap y-axis labels survive a data-only update. Name-based (series-name) heatmap y-axis labels no longer flip to numeric ticks after the first fast-path updateSeries.
  • Crossfilter charts stay rendered when a wrapper pushes an empty series. A React/Vue wrapper syncing its placeholder series prop right after mount no longer blanks a filter-mode chart; the engine re-asserts its aggregated series.
  • Group tooltip no longer skips the hovered chart, and horizontal-bar data labels honor offsetX.

TypeScript

chart.license is typed on the chart options.

Compatibility

  • No breaking API changes, and no renamed or removed options.
  • All chart types and free modules are never gated. The seven premium features run in trial mode with a watermark until a key is set; this is the only behavior change, and it does not block any functionality.
  • Bar/column layout is unchanged: the selection fix routes bar placement through the same math it already used, so rendered positions are identical.
  • New regression tests cover the license gating (per-feature on/off, in-use vs bundled, late key, SSR no-op), the selection/brush geometry consistency across all four gestures, and the crossfilter bin edges, alongside the existing unit, interaction, and end-to-end suites.

v6.4.0: 💎 Version 6.4.0

Compare Source

A feature release centered on heatmaps and a new bar chart race. Heatmaps gain a continuous numeric and datetime x-axis (cells positioned by real value, not by column index), optional canvas rendering for large grids, and a tooltip that now points at the cell it describes. The bar chart race animates bars and their labels as they re-rank. Two fixes round it out. Existing configs mostly render unchanged; three heatmap defaults change (tooltip placement, zoom, and label thinning), each noted below with how to restore the previous behavior.

✨ Features

Continuous numeric and datetime x-axis for heatmaps

On a numeric or datetime heatmap, cells are now placed at their real x value instead of being tiled one per column by index. Irregular spacing and gaps therefore render as real empty space: a missing hour is a gap in the grid, not a column squeezed away, and the axis shows sparse proportional date and time ticks rather than one label per cell. Rows stay categorical (one series per row).

Canvas cell rendering for large heatmaps

With chart.renderer: 'canvas' (or 'auto' past the render threshold) and the tree-shakable canvas feature imported, heatmap cells now paint to a single canvas instead of one <rect> per cell.

Heatmap cells SVG canvas
10,000 95 ms 27 ms
50,000 519 ms 170 ms
100,000 1,083 ms 388 ms
import ApexCharts from 'apexcharts'
import 'apexcharts/features/renderer-canvas'

const options = {
  chart: {
    type: 'heatmap',
    renderer: 'canvas', // or 'auto' to switch above rendererThreshold
  },
  // ...series
}
Bar chart race

A reorder update now animates into a bar chart race. When you re-sort the data and update the chart, the bars slide to their new ranks and their category labels ride along automatically (whenever dynamicAnimation is on). Two opt-in flags complete the effect: dataLabels.animate rides each value label to its bar's new position, and dataLabels.countUp tweens the number from its previous value.

const options = {
  chart: {
    type: 'bar',
    animations: { dynamicAnimation: { speed: 800 } },
  },
  plotOptions: { bar: { horizontal: true } },
  dataLabels: {
    enabled: true,
    animate: { enabled: true }, // value labels ride to the new rank
    countUp: { enabled: true }, // and count up or down from the last value
  },
}
// On each frame, re-sort your data and call updateOptions with the new series
// and categories. Bars, category labels, and value labels animate to the new
// order together.

Both label flags are off by default and apply to bar and column charts. Rotated axis labels ride correctly too.

🔧 Behavior changes (heatmap defaults)

The heatmap tooltip is anchored above the cell

The heatmap tooltip now sits centered above the hovered cell with a downward arrow pointing at it, flipping below when the cell is against the top edge.

🐛 Fixes

  • Light series no longer wash to white on hover. The lighten hover filter pushed already-bright fills all the way to white, so light-colored series lost their hue when hovered. The filter now preserves the color.
  • dataReducer no longer mutates your data. With zoom-aware downsampling active, the reduced (windowed) view was written back into the original series array, which is shared by reference, so later re-renders started already downsampled and could never recover the full-resolution points. The reducer now operates on a detached copy, leaving your input intact.
  • Custom tooltips keep their arrow. A tooltip.custom function replaced the tooltip's inner HTML, which discarded the arrow element. The arrow is now preserved across custom content, for every chart type.

TypeScript

dataLabels.animate and dataLabels.countUp (bar chart race) are typed on ApexDataLabels.

Compatibility

  • No breaking API changes, and no renamed or removed options.
  • Three heatmap defaults change (tooltip placement, zoom off, y-label thinning), each with a documented opt-out above.

v6.3.0: 💎 Version 6.3.0

Compare Source

A performance release focused on updates. updateSeries is now genuinely incremental: a data-only update repaints the series and refreshes the axis chrome in place instead of tearing the chart down and rebuilding it, so streaming and frequently-updating charts are several times faster. Large-series initial render is also markedly quicker from shared parsing work. There are no API changes and no new options: the rendered output is verified identical to 6.2.0, so existing configs render exactly as before, just faster.

The numbers below are 5-trial medians (initial render) and per-cycle medians (updates) from the reproducible harness behind the "100,000 Points" rendering benchmark, measured back to back on one machine (headless Chromium, animations off, identical seeded data).

⚡ Performance

updateSeries is now incremental

Previously every updateSeries call re-ran the full render pipeline: parse, re-layout, and a complete DOM rebuild. It now takes a fast path that repaints only the series layer and, when the axis scale changes, redraws the grid and axes in place within the frozen layout. The canvas renderer repaints its existing bitmap instead of recreating the backing store. Anything the fast path cannot reproduce exactly (a change in series count or data length, collapsed or combo series, an active zoom) falls back to the full render automatically.

updateSeries cycle 6.2.0 6.3.0
50,000 points (canvas) 62.5 ms (16/sec) 4.1 ms (242/sec)
50,000 points (SVG) 66.7 ms (15/sec) 12.5 ms (80/sec)
10,000 points (canvas) 11.1 ms (90/sec) 1.3 ms (765/sec)
10,000 points (SVG) 11.1 ms (90/sec) 2.8 ms (362/sec)
Line and area initial render: roughly 2 to 3 times faster at high point counts

The parse pipeline no longer forces a deep clone of the series and several whole-series aggregate passes that most charts never read, and plain numeric [[x, y], ...] data now parses in a single typed pass that also computes the axis extrema inline (removing separate min/max scans). The path geometry itself was already fast; this release removes the surrounding per-render overhead.

Line, single series 6.2.0 6.3.0
100,000 points (canvas) 90 ms 29 ms
100,000 points (SVG) 106 ms 40 ms
50,000 points (canvas) 57 ms 25 ms
50,000 points (SVG) 65 ms 30 ms
10,000 points (canvas) 27 ms 19 ms
Scatter charts inherit the parsing wins

Scatter and bubble charts share the parse pipeline, so they pick up a portion of the same improvement without any scatter-specific work.

Scatter 6.2.0 6.3.0
50,000 points (canvas) 155 ms 120 ms
50,000 points (SVG) 571 ms 528 ms
20,000 points (canvas) 73 ms 60 ms

🐞 Fixes

  • Data-only updates no longer leak DOM nodes. Because the incremental path preserves the chart DOM across updates instead of clearing it, two transient elements that the full render had always discarded were accumulating: a stray crosshair backing rect and the y-axis crosshair tooltip container, added once per update. On a continuously updating chart this grew without bound. Both are now reused across updates, so the node count stays flat over any number of updates. This matters most for real-time and streaming dashboards.
  • Brushing or zooming after a linked-chart update works again. A chart updated in place by a crossfilter or linked view kept a stale reference to its grid geometry, so a subsequent range brush or drag-zoom drew an empty selection. It now reads the live geometry on each interaction.

🔧 Behavior changes (structural, not visual)

  • The DOM subtree is preserved across updateSeries. Data-only updates now keep and update the existing series, axis, and grid elements rather than replacing them. Rendered output (SVG path data and canvas pixels) is verified identical; code that re-queries chart elements after an update by class or attribute continues to work, but code that cached a specific element node reference from before an update and relied on it being replaced should re-query instead.

Compatibility

  • No new options, no changed defaults, no TypeScript changes.
  • SVG path output and canvas pixels are verified identical to 6.2.0 across the snapshot suite; the fast path is held to the full render's output by a pixel-level oracle and by format-equivalence tests on the new parse path.
  • Verified by the full unit, interaction, and end-to-end snapshot suites, plus new regression tests covering the incremental update path, the parse fast lane, and the per-update node-count guard.

v6.2.0: 💎 Version 6.2.0

Compare Source

A performance release. Large-series rendering is 30 to 45% faster in both renderers, and scatter charts create half the DOM nodes they used to. There are no API changes and no new options: the rendered output is verified byte-identical to 6.1.0, so existing configs render exactly as before, just faster.

The numbers below are 5-trial medians from the reproducible harness behind the "100,000 Points" rendering benchmark post (headless Chromium, animations off, identical seeded data).

⚡ Performance

Scatter and bubble charts: half the nodes, up to 45% faster

Markers now render into ONE apexcharts-series-markers group per series instead of one wrapper group per point. On a 50,000-point scatter that removes 50,000 groups, 50,000 event-delegation setups, and 50,000 clip-path writes from every render.

Scatter (SVG) 6.1.0 6.2.0
5,000 points 109 ms 69 ms
20,000 points 395 ms, 40,100 nodes 249 ms, 20,102 nodes
50,000 points 1,042 ms 575 ms

Per-point interactivity is unchanged: tooltips, dataPointMouseEnter / dataPointMouseLeave / dataPointSelection, marker hover states, and selection filters all read their identity from the marker paths themselves and keep working exactly as before. Discrete markers, per-point fillColor, bubble z-scaling, and null-value markers are unaffected.

Line and area charts: 36 to 43% faster at high point counts

Plain straight line and area series now take a numeric fast path: pixel coordinates are computed in one tight loop and the path string is assembled in a single join, skipping the per-point machinery that dominated large renders. Anything the fast path cannot reproduce exactly (null gaps, visible markers, data labels, stacking, combo charts, smooth and stepped curves) automatically falls back to the previous code path. The d attribute output is byte-identical either way.

Line, single series 6.1.0 6.2.0
100,000 points (SVG) 161 ms 103 ms
100,000 points (canvas) 166 ms 95 ms
50,000 points (SVG) 89 ms 63 ms
updateSeries cycle, 10,000 points 25 ms 16 ms

The updateSeries improvement applies to both renderers, so streaming and frequently-updating charts benefit as well.

Canvas renderer: batched marker painting

The canvas renderer (apexcharts/features/renderer-canvas) now paints markers as style batches: one fill/stroke state application per run of same-style markers, so a uniform single-series scatter collapses to a single batch. Non-circle marker shapes (square, triangle, diamond, star, cross, plus) reuse one cached geometry per shape and size, translated per marker, instead of building a path string and parsing it for every point. Line and area series painted on canvas consume the fast path's numeric coordinates directly, with no path-string parse at all.

🔧 Behavior changes (structural, not visual)

  • One markers group per series. If custom CSS or JavaScript targeted the per-point .apexcharts-series-markers wrapper groups in scatter or bubble charts (for example, selecting the nth group to reach the nth point), there is now a single such group per series. The .apexcharts-marker paths inside it, including their rel, j, index, cx, cy, and default-marker-size attributes, are unchanged, so selectors that address markers directly keep working.

Compatibility

  • No new options, no changed defaults, no TypeScript changes.
  • SVG path output (d attributes) and canvas pixels are byte- and pixel-identical to 6.1.0 across the snapshot suite; only the wrapper-group structure noted above differs.
  • Verified by the full unit, interaction, and end-to-end snapshot suites, plus new regression tests covering the series-level marker groups, the canvas marker batching, and the line fast path's byte-identity against the previous geometry code.

v6.1.0: 💎 Version 6.1.0

Compare Source

A focused follow-up to 6.0. The Measure ruler graduates into a first-class toolbar tool you can pre-select, toolbar tools can now be toggled off, and two interaction bugs are fixed. Everything is backward compatible: existing configs render unchanged.

✨ Features

Measure ruler in the toolbar

The measure / delta ruler (shipped in 6.0) is now a built-in toolbar tool, so it can be armed with a click instead of holding the measure key. The button appears automatically whenever the ruler is enabled, and can be pre-selected so the plot loads ready to measure.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/measure'

const options = {
  chart: {
    measure: { enabled: true },
    toolbar: {
      autoSelected: 'measure',   // pre-select the ruler on load
      tools: { measure: true },  // default; set false to keep it key-only
    },
  },
}
  • The button shows only when chart.measure.enabled is true. tools.measure accepts true / false or a custom SVG string, like the other tools.
  • toolbar.autoSelected now also accepts 'measure', so the plot loads armed and ready to drag with no key held and no click. The m key still works.
  • Selecting the ruler is mutually exclusive with zoom / pan / selection. The icon matches the rest of the toolbar and follows the light / dark themes.

🔧 Behavior changes (on by default)

Toolbar tools toggle off on re-click

Clicking an already-selected zoom, pan, selection, or measure icon now deselects it, leaving the chart with no active tool. Previously those buttons were one-way (clicking the active tool did nothing). This makes the ruler's on / off state obvious and lets you drop back to a plain, gesture-free chart.

TypeScript

toolbar.tools.measure, the 'measure' value for toolbar.autoSelected, and the toolbar.measure locale string are all typed.

v6.0.0: 💎 Version 6.0.0

Compare Source

The largest release in the library's history. Version 6 turns a chart from a picture you look at into a surface you investigate, author, and share. Most of what follows is opt-in and tree-shakeable; existing configs keep working unchanged, and the zero-dependency, SVG-first identity is intact.

Two behaviors change by default (both respect prefers-reduced-motion and the existing dynamicAnimation.enabled escape hatch): data updates that add or remove points now animate coherently, and mobile pinch/pan gestures are on. See Fixes for the details.

✨ Features

Weave: public plugin platform

Publish reusable chart plugins to npm against a stable, versioned API. A plugin draws into its own sandboxed layer and subscribes to lifecycle hooks; it never touches raw internal state.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/weave'

ApexCharts.registerPlugin({
  name: 'watermark',
  apiVersion: 1,
  setup(api) {
    api.on('draw', ({ layer, scales }) => {
      layer.text({ x: 10, y: 20, text: 'ACME', size: '12px' })
    })
  },
})

// activate per chart
const options = { plugins: [{ name: 'watermark' }] }
  • api.layer is a plugin-owned drawing surface (path/line/rect/circle/text); api.scales converts data to pixels; api.data, api.theme, and api.store round out the facade.
  • apiVersion gates the contract so raw internals can keep changing safely. ApexCharts.unregisterPlugin(name) exists for tests and hot reload.
Strata: hybrid SVG + canvas renderer

Break the SVG node ceiling without leaving SVG behind. Below a threshold the output is identical SVG; above it, only the series layer becomes a <canvas> while axes, grid, tooltips, annotations, and exports stay SVG.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/renderer-canvas'

const options = {
  chart: { renderer: 'auto', rendererThreshold: 8000 }, // 'svg' | 'canvas' | 'auto'
}
// chart.getActiveRenderer() reports what is in use
  • Canvas is live for line, area, bar, column, scatter, and candlestick, with shared tooltip, crosshair, zoom, pan, hover and legend dimming, and PNG/SVG export all working.
  • Falls back to SVG automatically for canvas-unsupported features (pattern/image fills, color-matrix state filters). Per-point selection visuals and keyboard traversal on canvas remain SVG-only for now.
Marks: composable custom series types

Register a renderItem(datum, scales, api) function and get a first-class series: events, shared tooltip, legend, and keyboard navigation all work with no extra wiring.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/marks'

ApexCharts.registerSeriesType('lollipop', {
  renderItem({ x, y, api, color }) {
    api.line({ x1: x, y1: api.zeroY, x2: x, y2: y, stroke: color })
    api.circle({ cx: x, cy: y, r: 5, fill: color })
  },
})

const options = { series: [{ type: 'lollipop', data: [[0, 3], [1, 6], [2, 4]] }] }

Dumbbell, lollipop, and bullet ship as samples. Built-in type names are guarded against shadowing.

Rewind: history and undo/redo

Generic Ctrl-Z over a command journal. Zooms, series toggles, option changes, and annotation edits are recorded; high-frequency gestures coalesce into a single step.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/history'

const options = { chart: { history: { enabled: true, maxDepth: 100, coalesceMs: 250 } } }
// chart.history.undo(), .redo(), .jump(id), .transaction(fn, { label })
Perspectives: shareable view state

Serialize the exact view (zoom window, hidden series, selection, annotations, theme) into a compact token you can put in a URL and restore anywhere.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/perspectives'

const token = chart.perspectives.capture()
const url = chart.perspectives.toURL()      // href with #apex=<token>
chart.perspectives.apply(token, { animate: true })
// also: .save(name), .list(); static ApexCharts.perspectives.fromURL(href)
Facet: design tokens and OS-aware themes

Charts read --apx-* CSS custom properties from the cascade, follow the operating system's light/dark and contrast preferences with no JS, and can reference named brand themes.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/facet'

ApexCharts.registerTheme('brand', { palette: ['#&#8203;4f46e5', '#&#8203;0ea5e9'], tokens: { accent: '#&#8203;4f46e5' } })

const options = { theme: { follow: 'os', name: 'brand' } }
:root { --apx-accent: #&#8203;4f46e5; --apx-grid: #e5e7eb; --apx-surface: #fff; }

chart.refreshTokens() re-reads the cascade after a runtime token change that does not itself trigger a render.

Cadence: pluggable easing

chart.animations.easing accepts a named curve, a cubic-bezier array, or a function. The default is unchanged, so existing charts animate exactly as before.

const options = { chart: { animations: { easing: 'easeOutBack' } } } // or [0.34, 1.56, 0.64, 1], or (t) => t*t
// ApexCharts.registerEasing('bounce', (t) => /* ... */)

A data-change override is available via chart.animations.dynamicAnimation.easing.

Linked Views: crossfilter and cross-chart coordination

Coordinate a group of charts without wiring. In highlight mode, brushing one chart dims the non-matching marks in the others (no redraw). A real crossfilter engine adds categorical click-filters, range brushes, a shared data-table, and a heatmap 2D matrix target.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/link'

// highlight mode, per chart
const options = { chart: { group: 'sales', link: { enabled: true, mode: 'highlight', dimOpacity: 0.2 } } }

// or a shared crossfilter engine
const cf = ApexCharts.crossfilter({ id: 'sales', records })
Ink Layer: direct-manipulation annotation authoring

Annotations become draggable and resizable, with click-to-create, snap to gridlines, and a floating editor card (inline rename, recolor, bold, font size, marker size and shape, delete). Every edit is undoable when Rewind is enabled.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/ink'

const options = { chart: { ink: { enabled: true, palette: true, snap: true } } }
// fires annotationDragged, annotationEdited, annotationStyled, annotationDeleted
Measure ruler

Hold a key and drag to read the change, percent, range, and slope between two points; on release the ruler pins as a data-anchored overlay that re-projects on zoom and resize.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/measure'

const options = { chart: { measure: { enabled: true, mode: 'span', key: 'm', pinOnRelease: true } } }
// or drive it from code: chart.startMeasure(), chart.stopMeasure(), chart.clearMeasures()
// fires `measured`

mode: 'span' is the finance-style vertical band with a change/percent/range readout; mode: 'free' is a diagonal ruler between two arbitrary points. Styling resolves through --apx-measure-* tokens.

Context menu (Radial Actions)

Right-click or long-press a data point for verbs that act at that exact point rather than chart-wide.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/context-menu'

const options = {
  chart: {
    contextMenu: {
      enabled: true,
      items: ['annotate', 'xline', 'yline', 'measure', {
        id: 'copy', label: 'Copy value',
        onClick: (ctx, { x, y, seriesIndex, dataPointIndex }) => {},
      }],
    },
  },
}

Built-in annotate / xline / yline items are ink-managed when the ink feature is bundled (they open the floating editor and undo via Rewind).

Storyboard: scroll-driven choreography (scrollytelling)

Pair prose sections with saved views. Scrolling a beat past the viewport trigger applies its view; scrolling back reverses it. Each beat can also merge an updateOptions payload so it can restyle or morph chart.type inside one animated transition.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/storyboard' // includes Perspectives

chart.storyboard.bind({
  beats: [
    { selector: '[data-apex-beat="1"]', view: { window: { xaxis: { min: 0, max: 10 } } } },
    { selector: '[data-apex-beat="2"]', view: { collapsed: [1] }, options: { chart: { type: 'area' } } },
  ],
})
// chart.storyboard.goTo(beat), .current(), .unbind(); fires beatChange
Real-time streaming: constant-velocity scroll

Rolling-window updates now scroll at constant velocity instead of warping in place, and chart.streaming bounds memory for long-running feeds.

const options = { chart: { streaming: { enabled: true, maxPoints: 100000 } } }
// appendData() trims each series to maxPoints (or the visible xaxis.range window)

The scroll animation itself needs no opt-in: any update that continues the previous window (appendData, or a shifted fixed-length updateSeries) translates smoothly.

🔧 Behavior changes (on by default)

Coherent variable-length data transitions

Updates that change the number of data points now animate as one coordinated motion instead of popping. Appended bars grow from the baseline, removed bars shrink into ghosts and fade out, line and area fills reshape over the union of old and new points (so they can never tear), and markers, bubbles, and axis tick labels ride along on the same clock. This also gives scatter and bubble charts dynamic-update animations for the first time, and bubbles tween their radius on z changes. Zoom re-projections animate their marks and ticks too.

Disable per chart with chart.animations.dynamicAnimation.enabled: false. Skipped automatically above chart.animations.largeDatasetThreshold and when prefers-reduced-motion is set.

Native-feeling mobile gestures (Momentum)

Two-finger pinch-zoom around the centroid, two-finger pan, and kinetic inertia after a one-finger flick, with axis rails so a vertical swipe still scrolls the page. Configurable via chart.zoom.pinch and chart.pan.inertia.

🐛 Fixes

  • Scatter jitter zoom: zooming a jitter strip plot now snaps the window to whole bands, so x-axis labels no longer vanish on zoom-in and the first and last dot clouds are no longer half-cropped on zoom-out.
  • render() is idempotent: a repeated render() call (including a framework double-invoking an effect) returns the same promise instead of building a duplicate chart in the same element. destroy() clears it so an instance can render fresh; a rejected render clears itself so callers can retry.
  • Legend toggle: hideSeries / showSeries / toggleSeries no longer silently no-op under strict CSS selector engines (the series lookup no longer relies on an escaped-colon attribute selector).
  • Area morph: fixed a long-standing malformed pathFrom (double z) that fed the animation engine an invalid command list on area updates.

📦 Tree-shaking

Every feature above ships as a tree-shakeable entry (apexcharts/features/*) registered through the feature registry; the core stays lean. See the tree-shaking guide for the complete list of entry points.

TypeScript

Full type definitions ship with the package (no @types/* install). 6.0 adds types for every new config namespace and API, plus the SSR statics (renderToString, renderToHTML, hydrate, hydrateAll, isHydrated).

v5.16.0: 💎 Version 5.16.0

Compare Source

✨ Features
Drilldown navigation (opt-in)

Click a data point to drill into a child level, with a breadcrumb trail and back navigation. Supported on bar, column, pie, donut, treemap, and heatmap. Tree-shakeable: import the feature and enable it.

import ApexCharts from 'apexcharts'
import 'apexcharts/features/drilldown'

const options = {
  chart: {
    type: 'bar',
    drilldown: {
      enabled: true,
      series: [
        { id: 'fruits', name: 'Fruits', data: [{ x: 'Apple', y: 40 }, { x: 'Banana', y: 30 }] },
      ],
      // breadcrumb: { show: true, position: 'top-left', rootLabel: 'All' },
      // animation: { zoomFromPoint: true }, // unfold the child from the clicked point
      // onDrillDown: async ({ point }) => fetchChild(point), // async level loading
    },
  },
  series: [{ name: 'Categories', data: [{ x: 'Fruits', y: 70, drilldown: 'fruits' }, { x: 'Vegetables', y: 55 }] }],
}
  • Child levels are declared inline in chart.drilldown.series, or fetched on demand via onDrillDown.
  • Breadcrumb is configurable (position, separator, rootLabel, formatter) and includes a back-arrow.
  • Optional animation.zoomFromPoint unfolds the child level outward from the clicked point (and folds back on drill-up).
Pie / donut external (outer) data labels with leader lines (opt-in)

Render each slice's name outside the pie, connected by a leader line, so users no longer need to map legend colors back to slices. Pie and donut only (ignored for polarArea). The percentage keeps rendering inside the slice.

plotOptions: {
  pie: {
    dataLabels: {
      external: {
        show: true,
        // formatter: (name, { percent }) => [name, percent.toFixed(1) + '%'],
        // connector: { show: true, width: 1, length: 16, gap: 6 },
      },
    },
  },
}
Scatter jitter: strip plots and overplotting (opt-in)

Spread overlapping scatter points apart. Two uses, one engine. Offsets are in axis units, deterministic (SSR-safe), and applied to the drawn positions only, so tooltips still show the true values.

  • Strip plots: pass compact { x: 'Category', y: [v1, v2, ...] } data. Each category becomes a band and its values scatter horizontally within it. Every value is a real, hoverable marker; the sticky tooltip follows the hovered dot.
  • Overplotting: on ordinary { x, y } data, add small random offsets so dense clusters fan out.
plotOptions: { scatter: { jitter: { enabled: true, x: 0.35 /*, y: 0, distributed: false */ } } },
series: [
  { name: 'Frankfurt', data: [{ x: 'Frankfurt', y: [120, 118, 130, 109, 142] }] },
  { name: 'Mumbai', data: [{ x: 'Mumbai', y: [182, 176, 195, 168, 201] }] },
]

Marker styling reuses the standard markers / colors / fill config; set jitter.distributed: true to color each band separately.

Data reducer for range charts

chart.dataReducer now downsamples rangeArea and rangeBar series via min-max bucket aggregation (preserving the visual extremes of each bucket), complementing the existing LTTB reduction for line/area.

chart: { dataReducer: { enabled: true, threshold: 500, targetPoints: 250 } }
🐛 Fixes
  • Drilldown: reset the legend-collapse state when drilling so a child level is not rendered with a parent's series hidden.

v5.15.2: 💎 Version 5.15.2

Compare Source

Fixes

Draw-animation frame no longer touches a destroyed chart

An animated chart (e.g. an area chart) schedules a requestAnimationFrame during render() to run its mask-reveal / draw animation. If the chart was destroyed before that frame fired, the stale callback ran against already-cleared DOM and threw:

TypeError: Cannot read properties of null (reading 'node')   // in runMaskReveal

The classic trigger is React StrictMode, which mounts → unmounts → remounts a component in development: the first mount queues the animation frame, the unmount calls destroy() (which nulls w.dom.elDefs), and the queued frame then fires against the torn-down chart. Any sufficiently rapid unmount hit the same race.

The fix adds an internal isDestroyed flag, set by destroy() (but not by updates), that the deferred draw-animation callbacks - mask reveal, stroke draw, and bulk reveal - check and bail on before touching the DOM. The flag is cleared on the next render, so re-mounting re-arms animations normally.

This complements the detached-chart destroy() fix in 5.15.1; together they resolve the teardown crashes tracked in react-apexcharts#602.

v5.15.1: 💎 Version 5.15.1

Compare Source

A small patch release with a single stability fix: charts that are torn down before they ever mount no longer throw.


Fixes

destroy() no longer throws on an un-mounted / detached chart

Calling destroy() (or an internal clear()) on a chart that never finished rendering threw:

TypeError: Cannot read properties of undefined (reading 'node')

This happened when a chart was constructed against an element that wasn't connected to the DOM - so create() bailed out early before building the SVG, leaving w.dom.Paper undefined - and the chart was then destroyed. Common triggers:

  • A React useEffect cleanup (or a Vue unmounted hook) tearing the chart down before the element was ever attached.
  • A queued resize/update() firing after the host element had already been removed.

The teardown path now guards on the SVG actually having been created, cancels any pending resize redraw, and tolerates a missing Apex._chartInstances registry, so destroying a never-mounted chart is a safe no-op.

Fixes react-apexcharts#602 and vue-apexcharts#256.

v5.15.0: 💎 Version 5.15.0

Compare Source

New Features

Violin chart type
Screenshot 2026-06-11 at 4 15 00 PM

A new, tree-shakeable chart.type: 'violin' that renders a kernel-density curve for each category, with an optional overlay of the individual observations ("jitter") that produced it.

chart: {
  type: 'violin',
},
plotOptions: {
  violin: {
    bandwidthScale: 1,       // multiplies the density-derived half-width
    normalize: 'individual', // 'individual' → each violin scaled to its own peak
                             // 'group'      → all violins share one scale (widths track density across categories)
    points: {
      show: true,
      shape: 'circle',        // 'circle' | 'square'
      size: 2.5,              // radius (px)
      jitter: 0.5,            // 0..1 fraction of the half-width to scatter within
      constrainToViolin: true,// clamp jitter to the density width at each value
      maxPoints: 3000,        // cap per violin; excess is stride-thinned
      opacity: 0.9,
      fillColor: 'series-dark',// 'series-dark' | 'series' | any literal colour
      strokeColor: '#fff',
      strokeWidth: 1,
      // optional colorScale: { colors: [...], min, max, steps } to colour each dot by value
    },
  },
},
  • Available as a tree-shakeable entry: import ApexCharts from 'apexcharts/violin', or via the full bundle.
  • Supports horizontal orientation and bimodal (multi-modal) densities.
  • The jitter overlay reveals gradually as the violin path animates in (no instant pop-in).
Box-plot jitter overlay
Screenshot 2026-06-11 at 4 15 45 PM

Box plots can now overlay the raw observations behind each box, via plotOptions.boxPlot.points. It's off by default and inert unless a data point supplies a points: number[] array, so existing box-plot charts are unchanged.

plotOptions: {
  boxPlot: {
    points: {
      show: true,
      shape: 'circle',  // 'circle' | 'square'
      size: 2.5,
      jitter: 0.5,      // 0..1 fraction of the box half-width to scatter within
      maxPoints: 3000,  // cap per box; excess is stride-thinned
      opacity: 0.9,
      fillColor: 'series-dark',
      strokeColor: '#fff',
      strokeWidth: 1,
    },
  },
},

v5.14.0: 💎 Version 5.14.0

Compare Source

✨ New Features

Heatmap gradient legend

An opt-in continuous gradient legend for heatmaps that replaces the categorical legend with a color strip and a hover-tracking arrow.

  • Honors legend.position (top / right / bottom / left) and a new align config (start / center / end).
  • Strip length accepts px or percent (default '70%').
  • Stops are derived from colorScale.ranges or sampled from the same shade function the cells use, rendered as a smooth midpoint-anchored gradient (green → blue → yellow → red) that matches the shaded cells.
  • Per-band hover: hovering a range highlights the cells in that range and dims the rest.
  • The heatmap legend now renders for single-series charts too.
Value-proportional pyramid geometry

chart.type: 'pyramid' now matches the geometry users expect: a single continuous triangle whose stages each own a vertical share proportional to their value, with no gaps between segments.

  • Stages are trapezoids bounded by the triangle envelope (apex at top, base at gridWidth) sized by cumulative-value share.
Chart-type morph animations

A new, optional, tree-shakeable feature that tweens between chart types instead of the old destroy-and-recreate flicker.

chart: {
  animations: {
    chartTypeMorph: { enabled: true, speed: 600 }
  }
}

Loaded on demand via apexcharts/features/morph. It captures the old SVG paths from the DOM before destroy, maps each one onto the new chart-type's element identity, and seeds the new paths so the existing PathMorphing engine interpolates between them. When the source/target types or series shapes are incompatible it falls back to an instant snap.

  • Supported pairs: bar ↔ {pie, donut, radialBar, polarArea}, plus the trivial pie ↔ donut ↔ polarArea cases, and cross-type morphs involving funnel / pyramid / gauge.

🐛 Fixes

  • heatmap: fix two color-mapping bugs in the shared treemap/heatmap helper.
  • tooltip: align the combo-chart crosshair with the bar on a numeric x-axis.
  • annotations: preserve configured opacity on x-axis range rects.
  • toolbar: use the rotate-ccw icon for the reset-zoom button.
  • svg: fix a concat error for SVG paths starting in M 0 0 (invalid-path edge case).
  • types: add toolbar.menu to the ApexLocale type.

v5.13.0: 💎 Version 5.13.0

Compare Source

This release focuses on a major visual and behavioral overhaul of tooltips, gauges, and the toolbar, alongside a new zoom-aware LTTB downsampler for very large datasets, a new multi-axis zero-alignment option, and a tightening of the public TypeScript surface.


Features

feat(tooltip): modernized positioning, arrows, and a11y

Tooltip box and arrow now anchor off the bar's rendered DOM rect fixing column/datetime alignment in stacked and grouped charts. Adds a connector arrow (default on) and context-aware placement

  • New options:
    • tooltip.arrow: boolean (default true) — render a connector arrow pointing at the data point.
feat(gauge): needle options and

Note

PR body was truncated to here.


Configuration

📅 Schedule: (in timezone Asia/Jerusalem)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added the renovate label Jul 21, 2026
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
b2b-react-sample-app Ready Ready Preview Aug 5, 2026 12:10pm

Comment thread package-lock.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants