apexcharts-skill 4.0.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.cursorrules CHANGED
@@ -16,14 +16,14 @@ v5 and v6 configs keep working, with two v7.0 changes: `plotOptions.bar.borderRa
16
16
  import 'apexcharts/features/drilldown' // a Tier 2 feature
17
17
 
18
18
  Tier 2 chart types, `import 'apexcharts/<type>'` (script tag `dist/<type>.js`): `unit` (also for `waffle`), `sunburst` and `violin` (all three since 8.0), `icicle` (7.6), and `raincloud` (`apexcharts/raincloud` brings violin plus the raincloud feature; script tags `dist/violin.js`, then `dist/features/raincloud.js`).
19
- Tier 2 features, `import 'apexcharts/features/<name>'` (script tag `dist/features/<name>.js`): drilldown, waterfall, dumbbell, streamgraph (since 8.0), highlight-filter (7.9), trellis, storyboard, perspectives, ink, renderer-canvas, link, measure, history, context-menu (since 7.0). Waterfall, dumbbell and streamgraph are chart types whose renderer is in the default bundle, so next to it add only the feature.
19
+ Tier 2 features, `import 'apexcharts/features/<name>'` (script tag `dist/features/<name>.js`): radial-targets (8.5, for `plotOptions.radialBar.targets`), drilldown, waterfall, dumbbell, streamgraph (since 8.0), highlight-filter (7.9), trellis, storyboard, perspectives, ink, renderer-canvas, link, measure, history, context-menu (since 7.0). Waterfall, dumbbell and streamgraph are chart types whose renderer is in the default bundle, so next to it add only the feature.
20
20
  `apexcharts/features/all` is the Tier 1 set and pulls in none of them.
21
- Full bundle (v8.0): `import ApexCharts from 'apexcharts/full'` (script tag `dist/apexcharts.full.min.js`) carries every chart type and feature and needs no add-on import. Gzipped at 8.0.0: default bundle 263,188 B, full bundle 381,135 B.
22
- A missing import is named in the console: a Tier 2 chart type makes `render()` reject; a waterfall, dumbbell or streamgraph draws an empty plot; a Tier 2 feature degrades where it can (a trellis renders as one chart; renderer: 'canvas' falls back to SVG). Unversioned CDN URLs serve 8.0; pin `apexcharts@7` to stay on 7.
21
+ Full bundle (v8.0): `import ApexCharts from 'apexcharts/full'` (script tag `dist/apexcharts.full.min.js`) carries every chart type and feature and needs no add-on import, except `apexcharts/features/ignite-ui` (8.8), which is in no bundle. Gzipped at 8.0.0: default bundle 263,188 B, full bundle 381,135 B.
22
+ A missing import is named in the console: a Tier 2 chart type makes `render()` reject; a waterfall, dumbbell or streamgraph draws an empty plot; a Tier 2 feature degrades where it can (a trellis renders as one chart; renderer: 'canvas' falls back to SVG; a gauge draws without its targets). Unversioned CDN URLs serve the latest 8.x release; pin a 7.x release to stay on 7.
23
23
 
24
- Premium (watermarked until an entitled premium/enterprise license): trellis, storyboard, link, ink, measure, context-menu, perspectives, history, highlight-filter, and the unit/waffle and raincloud chart types. Premium and Tier 2 are separate axes: since 8.0 every premium item is Tier 2, but renderer-canvas, drilldown, waterfall, dumbbell, streamgraph, sunburst, violin and icicle are Tier 2 and free.
24
+ Premium (watermarked until an entitled premium/enterprise license): trellis, storyboard, link, ink, measure, context-menu, perspectives, history, highlight-filter, and the unit/waffle and raincloud chart types. Premium and Tier 2 are separate axes: since 8.0 every premium item is Tier 2, but renderer-canvas, drilldown, radial-targets, waterfall, dumbbell, streamgraph, sunburst, violin and icicle are Tier 2 and free.
25
25
 
26
- On by default: coherent add/remove data-transition animations (they respect prefers-reduced-motion), and one-finger kinetic pan (`chart.pan.inertia`). Since v7.8, `dataLabels.avoidOverlap` nudges overlapping data labels apart (`false` to disable). Pinch-zoom and two-finger pan follow `chart.zoom.pinch: 'auto'`: on only where the toolbar reset button is present.
26
+ On by default: coherent add/remove data-transition animations (they respect prefers-reduced-motion), and one-finger kinetic pan (`chart.pan.inertia`). Since v7.8, `dataLabels.avoidOverlap` nudges overlapping data labels apart (`false` to disable). Pinch-zoom and two-finger pan follow `chart.zoom.pinch: 'auto'`: on only where the toolbar reset button is present. The mouse wheel follows `chart.zoom.allowMouseWheelZoom: 'auto'`, the same gate, and since v8.3 it is cooperative: a bare wheel scrolls the page (with a short hint, `chart.zoom.wheelHint: false` hides it), and Ctrl/Cmd + wheel or a trackpad pinch zooms. `allowMouseWheelZoom: true` zooms on every wheel.
27
27
 
28
28
  ## Framework wrapper detection — check `package.json` first
29
29
 
@@ -41,7 +41,7 @@ Wrappers handle `destroy()` automatically on unmount, accept reactive props, and
41
41
  4. **`yaxis` must be an array** when using multiple y-axes. Each entry needs `seriesName`.
42
42
  5. **`tooltip.shared` and `tooltip.intersect` are mutually exclusive.**
43
43
  6. **Use `null` (not `undefined`)** for missing data points.
44
- 7. **`chart.stacked: true`** stacks `bar`, `area` and `line` series. In a mixed chart only the bar series stack unless `chart.stackOnlyBar: false`. `waterfall`, `dumbbell` and `streamgraph` force it off.
44
+ 7. **`chart.stacked: true`** stacks `bar`, `area` and `line` series. In a mixed chart only the bar series stack unless `chart.stackOnlyBar: false`. `waterfall`, `dumbbell` and `streamgraph` force it off. `chart.stackType: '100%'` draws shares of each stack's total; since v8.5 area and line stacks draw percentages too.
45
45
  8. **Responsive breakpoints** must be in ascending order.
46
46
  9. **For mixed/combo charts**, set `type` on each series object.
47
47
  10. **RadialBar values sit on the `plotOptions.radialBar.min` to `max` domain** (default 0 to 100, so percentages by default). Set `min` / `max` to plot raw values; a value outside the domain is clamped.
@@ -50,9 +50,9 @@ Wrappers handle `destroy()` automatically on unmount, accept reactive props, and
50
50
  13. **Tree-shaking**: `apexcharts/core` requires separate chart-type + feature imports. On it, `violin` and `raincloud` also need `apexcharts/bar`, and a raw-sample boxPlot or violin needs `apexcharts/features/stats`.
51
51
  14. **Aliases**: `funnel`/`pyramid` render through bar, `gauge` through radialBar. Use them as `chart.type` directly (no `plotOptions.bar.isFunnel`); covered by `apexcharts/bar` and `apexcharts/radialBar`.
52
52
  15. **`violin`** points use a density profile: `data: [{ x, y: { density: [[value, weight], ...], points?: [num] } }]`.
53
- 16. **`render()` is idempotent**: a repeated `render()` returns the same promise; still `destroy()` before a new instance on the same element.
53
+ 16. **`render()` is idempotent**: a repeated `render()` returns the same promise; still `destroy()` before a new instance on the same element. Since v8.1 `render()` after `destroy()` draws that instance afresh, and `updateOptions` / `updateSeries` on a destroyed chart warn and resolve instead of throwing.
54
54
  17. **Unknown `chart.type` throws (v7.9)** and the message names the closest type. `'column'` is a synonym for `'bar'`; `''` and `null` draw a line chart.
55
- 18. **A script tag names the exact version shown here**: `https://cdnjs.cloudflare.com/ajax/libs/apexcharts/8.2.0/apexcharts.min.js` or `https://cdn.jsdelivr.net/npm/apexcharts@8.2.0/dist/apexcharts.min.js`. Never write a 3.x or 4.x URL (`.../apexcharts/3.54.1/...`): those are releases from 2024 and early 2025. If the environment only accepts an older release, use the newest one it accepts with the same major version as these URLs.
55
+ 18. **A script tag names the exact version shown here**: `https://cdn.jsdelivr.net/npm/apexcharts@8.8.1/dist/apexcharts.min.js` (jsDelivr; cdnjs can lag a release by days, so use it only when the environment allows nothing else, with the newest version it lists). Never write a 3.x or 4.x URL (`.../apexcharts/3.54.1/...`): those are releases from 2024 and early 2025. If the environment only accepts an older release, use the newest one it accepts with the same major version as these URLs.
56
56
 
57
57
  ---
58
58
 
@@ -132,7 +132,7 @@ chart.destroy() // cleanup
132
132
 
133
133
  ```
134
134
  apexcharts # Default bundle: the standard types (see the box above) + the Tier 1 features
135
- apexcharts/full # Full bundle (v8.0): every chart type and feature; no add-on import needed
135
+ apexcharts/full # Full bundle (v8.0): every chart type and feature; no add-on import needed except ignite-ui
136
136
  apexcharts/core # Bare core (must register types + features manually)
137
137
  apexcharts/line # line, area, scatter, bubble, rangeArea
138
138
  apexcharts/bar # bar, column, rangeBar, funnel, pyramid (aliases)
@@ -179,6 +179,7 @@ apexcharts/features/waterfall # (v7.1) waterfall type (Tier 2 since v8)
179
179
  apexcharts/features/dumbbell # (v7.1) dumbbell type (Tier 2 since v8)
180
180
  apexcharts/features/streamgraph # (v7.1) streamgraph type (Tier 2 since v8)
181
181
  apexcharts/features/highlight-filter # (v7.9) part-of-whole highlight, highlightFilter (premium)
182
+ apexcharts/features/radial-targets # (v8.5) plotOptions.radialBar.targets on radialBar / gauge (free)
182
183
  apexcharts/features/trellis # (v7.0) small multiples (premium)
183
184
  apexcharts/features/storyboard # scrollytelling (premium; registers perspectives)
184
185
  apexcharts/features/perspectives # shareable view state (premium)
@@ -188,9 +189,12 @@ apexcharts/features/link # crossfilter / linked views (premium)
188
189
  apexcharts/features/measure # measure / delta ruler (premium)
189
190
  apexcharts/features/history # undo/redo (Rewind, premium)
190
191
  apexcharts/features/context-menu # right-click context menu (premium)
192
+
193
+ # IN NO BUNDLE, not even apexcharts/full (from 8.8.0, free, no licence key)
194
+ apexcharts/features/ignite-ui # follow an Ignite UI theme (--ig-* tokens) on the page
191
195
  ```
192
196
  (Cadence easing and real-time streaming are core: no feature import needed.)
193
- Script tags: a default-bundle page adds `dist/<type>.js` for a Tier 2 chart type and `dist/features/<name>.js` for a Tier 2 feature (raincloud: `dist/violin.js`, then `dist/features/raincloud.js`). Add-on tags may load before or after the ApexCharts script. `dist/apexcharts.full.min.js` already contains them all.
197
+ Script tags: a default-bundle page adds `dist/<type>.js` for a Tier 2 chart type and `dist/features/<name>.js` for a Tier 2 feature (raincloud: `dist/violin.js`, then `dist/features/raincloud.js`). Add-on tags may load before or after the ApexCharts script. `dist/apexcharts.full.min.js` already contains them all. Exception: `dist/features/ignite-ui.js` (from 8.8.0) is in no bundle, the full one included, so a full-bundle page adds its tag too (after `apexcharts.js` is the recommended order).
194
198
  Lean core channel (v7.0): `dist/apexcharts.core.js` plus per-type files such as `dist/line.js` and feature files such as `dist/features/legend.js`, for a page that needs less than the default bundle.
195
199
 
196
200
  ---
@@ -202,13 +206,15 @@ Lean core channel (v7.0): `dist/apexcharts.core.js` plus per-type files such as
202
206
  | `xaxis.labels.formatter` | `(value, timestamp?, opts?) => string` |
203
207
  | `yaxis.labels.formatter` | `(value, opts?) => string` |
204
208
  | `tooltip.x.formatter` | `(value, opts?) => string` |
205
- | `tooltip.y.formatter` | `(value: number \| null, opts?) => string`; `value` is `null` at a gap, so guard: `val == null ? 'n/a' : val.toFixed(2)` |
209
+ | `tooltip.y.formatter` | `(value: number \| null, opts?) => string \| null`; `value` is `null` at a gap, so guard: `val == null ? 'n/a' : val.toFixed(2)`. Returning `null` hides that row in a shared tooltip |
206
210
  | `tooltip.y.title.formatter` | `(seriesName, opts?) => string` |
207
211
  | `dataLabels.formatter` | `(value, opts?) => string \| number` |
208
- | `legend.formatter` | `(legendName, opts?) => string` |
212
+ | `legend.formatter` | `(legendName, opts?) => string` (HTML; `legendName` is raw, so escape it before adding markup) |
209
213
  | `plotOptions.pie.donut.labels.total.formatter` | `(w) => string` |
210
214
  | `plotOptions.radialBar.dataLabels.value.formatter` | `(val) => string` |
211
215
 
216
+ Names are text (v8.4): series names, categories, goal names and tree node names are escaped in the legend and tooltip, so markup in them shows literally. Markup a formatter returns still renders.
217
+
212
218
  ---
213
219
 
214
220
  ## Pitfalls — ❌ Wrong vs ✅ Correct
@@ -234,8 +240,9 @@ Lean core channel (v7.0): `dist/apexcharts.core.js` plus per-type files such as
234
240
  ✅ `yaxis: [{ seriesName: 'Revenue', title: {...} }, { seriesName: 'Profit', opposite: true }]`
235
241
 
236
242
  ### 6. Both shared and intersect tooltips
237
- ❌ `tooltip: { shared: true, intersect: true }`
243
+ ❌ `tooltip: { shared: true, intersect: true }` (constructing the chart throws)
238
244
  ✅ `tooltip: { shared: true, intersect: false }` or `{ shared: false, intersect: true }`
245
+ `tooltip.visible: false` (v8.5) keeps hover events and crosshairs but draws no tooltip box; `enabled: false` turns hover off.
239
246
 
240
247
  ### 7. undefined for missing data
241
248
  ❌ `data: [10, undefined, 30]`
@@ -282,6 +289,10 @@ On Node, plain `apexcharts` also resolves to the SSR bundle (the `node` export c
282
289
  ❌ `import ApexCharts from 'apexcharts'; new ApexCharts(el, { chart: { type: 'sunburst' }, series }).render()`: `render()` rejects and the console names the missing import
283
290
  ✅ `import ApexCharts from 'apexcharts'; import 'apexcharts/sunburst'` (or `import ApexCharts from 'apexcharts/full'`)
284
291
 
292
+ ### 18. Ignite UI theme on the page without the add-on (from 8.8.0)
293
+ ❌ Loading an Ignite UI stylesheet and expecting charts to follow it: without the add-on the `--ig-*` tokens are ignored silently and `theme.designSystem` does nothing. Also ❌ `theme: { mode: 'light' }` on a page with a dark Ignite UI theme: a pinned mode blocks the dark variant.
294
+ ✅ `import 'apexcharts/features/ignite-ui'` once, before the first render (script tag: `dist/features/ignite-ui.js` after `apexcharts.js`), and leave `theme.mode` unset. No extra licence key. Ranking: explicit options > the chart's CSS variables > `--apx-*` tokens > named theme / explicit palette > `--ig-*` > defaults. `theme: { designSystem: false }` turns it off for one chart; `theme: { tokens: false }` turns off `--apx-*` and Ignite UI together. After swapping the Ignite UI stylesheet, call `chart.refreshTokens()`. New core tokens in 8.8.0: `--apx-font-family`, `--apx-radius-factor`.
295
+
285
296
  ---
286
297
 
287
298
  ## API Methods
@@ -304,6 +315,7 @@ On Node, plain `apexcharts` also resolves to the SSR bundle (the `node` export c
304
315
  | `clearAnnotations()` | Remove all. |
305
316
  | `dataURI()` | Export as image (needs features/exports). |
306
317
  | `exportToCSV()` | Export as CSV (needs features/exports). |
318
+ | `refreshTokens()` | Re-read `--apx-*` tokens (and `--ig-*` with the ignite-ui add-on) after a CSS change that does not render. From 8.8.0 `ApexCharts.exec('<chart.id>', 'refreshTokens')` reaches it too and returns the update Promise (same as `ApexCharts.getChartByID(id).refreshTokens()`). |
307
319
 
308
320
  ### Static Methods
309
321
 
package/README.md CHANGED
@@ -27,7 +27,7 @@ This skill targets **ApexCharts v8** (v5, v6 and v7 configs keep working, apart
27
27
  - **30 `chart.type` values**: line, area, bar (with its `column` synonym), pie, donut, radialBar, scatter, bubble, heatmap, candlestick, boxPlot, violin, histogram, radar, polarArea, rangeBar, rangeArea, treemap, funnel, pyramid, gauge, sunburst, icicle, unit, waffle, waterfall, dumbbell, streamgraph, raincloud
28
28
  - **Correct data formats** for every chart type
29
29
  - **Common pitfalls** with wrong/correct code examples
30
- - **Feature platform**: small multiples (Trellis), plugins (Weave), canvas renderer (Strata), custom series (Marks), undo/redo (Rewind), shareable views (Perspectives), themes (Facet), easing (Cadence), crossfilter (Link), annotation authoring (Ink), measure ruler, context menu, storyboard, streaming, drilldown, part-of-whole highlight (Highlight filter), raw-sample statistics (Stats), unit-chart shape kit (`apexcharts/unit-shapes`), pictogram glyphs (`apexcharts/pictograms`)
30
+ - **Feature platform**: small multiples (Trellis), plugins (Weave), canvas renderer (Strata), custom series (Marks), undo/redo (Rewind), shareable views (Perspectives), themes (Facet), easing (Cadence), crossfilter (Link), annotation authoring (Ink), measure ruler, context menu, storyboard, streaming, drilldown, part-of-whole highlight (Highlight filter), radialBar and gauge targets (8.5), raw-sample statistics (Stats), unit-chart shape kit (`apexcharts/unit-shapes`), pictogram glyphs (`apexcharts/pictograms`), and the Ignite UI theming add-on (`apexcharts/features/ignite-ui`, 8.8.0)
31
31
  - **Bundle contents** (which chart types and features the default v8 bundle carries, which are opt-in imports, and the `apexcharts/full` bundle), tree-shaking, and the lean-core script-tag channel
32
32
  - **SSR** (server-side rendering) and hydration
33
33
  - **Framework integration**: React, Vue 3, Angular
package/SKILL.md CHANGED
@@ -9,14 +9,14 @@ description: >
9
9
  correct data formats, lifecycle, formatters, tree-shaking, SSR, and the feature
10
10
  platform (plugins, canvas renderer, custom series, small multiples, undo/redo,
11
11
  shareable views, themes, crossfilter, annotation authoring, storyboard, streaming,
12
- drilldown, highlight filter). Knows which chart types and features ship in the
12
+ drilldown, highlight filter, radialBar targets, Ignite UI theming). Knows which chart types and features ship in the
13
13
  default v8 bundle and which need an explicit import or the full bundle. In React /
14
14
  Vue / Angular projects, prefer the framework wrapper packages
15
15
  (`react-apexcharts`, `vue3-apexcharts`, `ng-apexcharts`) over the core API.
16
16
  metadata:
17
17
  author: ApexCharts
18
- version: "4.0.2"
19
- library_version: "8.0.0"
18
+ version: "4.2.0"
19
+ library_version: "8.8.1"
20
20
  category: data-visualization
21
21
  tags: [charts, visualization, javascript, typescript, svg, apexcharts]
22
22
  docs: https://apexcharts.com/docs/
@@ -57,19 +57,20 @@ metadata:
57
57
  > | `raincloud` | `apexcharts/raincloud` (the violin renderer plus the raincloud feature) | `dist/violin.js`, then `dist/features/raincloud.js` | 7.1 (new); needs violin since 8.0 |
58
58
  > | `drilldown`, and the `waterfall`, `dumbbell` and `streamgraph` chart types | `apexcharts/features/<name>` | `dist/features/<name>.js` | 8.0 |
59
59
  > | `highlight-filter` (`highlightFilter`) | `apexcharts/features/highlight-filter` | `dist/features/highlight-filter.js` | 7.9 (new) |
60
+ > | `radial-targets` (`plotOptions.radialBar.targets`) | `apexcharts/features/radial-targets` | `dist/features/radial-targets.js` | 8.5 (new) |
60
61
  > | `trellis`, `storyboard`, `perspectives`, `ink`, `renderer-canvas`, `link`, `measure`, `history`, `context-menu` | `apexcharts/features/<name>` | `dist/features/<name>.js` | 7.0 |
61
62
  >
62
63
  > Waterfall and dumbbell draw through rangeBar and streamgraph through rangeArea, which the default bundle has, so next to it you add only the feature. Storyboard registers Perspectives, so importing both costs no more than Storyboard alone.
63
64
  >
64
- > **The full bundle** (v8.0) loads everything at once: `import ApexCharts from 'apexcharts/full'` in a bundler, `dist/apexcharts.full.min.js` from a script tag. It carries every chart type and feature plus the unit-shapes and pictograms catalogs, and needs no add-on import (premium items stay license-gated). Gzipped at 8.0.0: default bundle 263,188 B, full bundle 381,135 B.
65
+ > **The full bundle** (v8.0) loads everything at once: `import ApexCharts from 'apexcharts/full'` in a bundler, `dist/apexcharts.full.min.js` from a script tag. It carries every chart type and feature plus the unit-shapes and pictograms catalogs, and needs no add-on import except the Ignite UI add-on (`apexcharts/features/ignite-ui`, v8.8), which is in no bundle (premium items stay license-gated). Gzipped at 8.0.0: default bundle 263,188 B, full bundle 381,135 B.
65
66
  >
66
- > **Nothing fails silently**: when the import is missing, the console names it. A Tier 2 chart type makes `render()` reject; a `waterfall`, `dumbbell` or `streamgraph` draws an empty plot; a Tier 2 feature degrades where it can (a trellis renders as one chart; `renderer: 'canvas'` falls back to SVG). Unversioned CDN URLs serve 8.0; pin `apexcharts@7` to stay on 7, where unit, sunburst, violin, drilldown, waterfall, dumbbell and streamgraph are still in the default bundle. The split began in v7.0, which moved the nine features in the last table row out of a default bundle that had carried every feature. See `references/tree-shaking.md` for the full tier table and `references/feature-platform.md` for each feature's API.
67
+ > **Nothing fails silently**: when the import is missing, the console names it. A Tier 2 chart type makes `render()` reject; a `waterfall`, `dumbbell` or `streamgraph` draws an empty plot; a Tier 2 feature degrades where it can (a trellis renders as one chart; `renderer: 'canvas'` falls back to SVG; a gauge draws without its targets). Unversioned CDN URLs serve the latest 8.x release; pin a 7.x release to stay on 7, where unit, sunburst, violin, drilldown, waterfall, dumbbell and streamgraph are still in the default bundle. The split began in v7.0, which moved the nine features in the last table row out of a default bundle that had carried every feature. See `references/tree-shaking.md` for the full tier table and `references/feature-platform.md` for each feature's API.
67
68
  >
68
69
  > **Other v7.0 breaking changes.** (1) `plotOptions.bar.borderRadiusWhenStacked` was dropped as dead config in v7.0 and is a **working option again in v7.4**: `'all'` (the default) rounds both stack ends, `'last'` rounds only the far end and leaves the baseline square. Do not delete it from a config. (2) `dataLabels.animate.enabled` now defaults to `true` (bar/column only): labels ride to their new position on a data update instead of snapping. Set `dataLabels: { animate: { enabled: false } }` for the old behavior. Everything else from v5 and v6 keeps working unchanged.
69
70
  >
70
- > **Behaviors that are on by default** (both respect `prefers-reduced-motion`): data updates that add/remove points animate coherently, and one-finger kinetic pan is enabled (`chart.pan.inertia`). Since v7.8, data labels that land on each other are nudged apart (`dataLabels.avoidOverlap`, see section 5). The two-finger gestures, pinch-zoom and two-finger pan, sit behind `chart.zoom.pinch`, which defaults to `'auto'`: **on only where the toolbar reset button is present**, so an unintended zoom is always undoable. `chart.zoom.allowMouseWheelZoom` is gated the same way. Set `pinch: true` to force the gestures on a toolbar-less chart, or see `chart.zoom.resetControl` (v7.4) for the other way to satisfy the gate.
71
+ > **Behaviors that are on by default** (both respect `prefers-reduced-motion`): data updates that add/remove points animate coherently, and one-finger kinetic pan is enabled (`chart.pan.inertia`). Since v7.8, data labels that land on each other are nudged apart (`dataLabels.avoidOverlap`, see section 5). The two-finger gestures, pinch-zoom and two-finger pan, sit behind `chart.zoom.pinch`, which defaults to `'auto'`: **on only where the toolbar reset button is present**, so an unintended zoom is always undoable. `chart.zoom.allowMouseWheelZoom` is gated the same way, and **since v8.3 its `'auto'` wheel is cooperative**: a bare wheel scrolls the page past the chart (showing a short "Use Ctrl + scroll to zoom" hint), and only Ctrl/Cmd + wheel or a trackpad pinch zooms. `allowMouseWheelZoom: true` restores the old wheel, which zooms on every scroll; `chart.zoom.wheelHint: false` hides the hint. Set `pinch: true` to force the gestures on a toolbar-less chart, or see `chart.zoom.resetControl` (v7.4) for the other way to satisfy the gate.
71
72
  >
72
- > **Premium features and licensing.** Nine features are premium: `trellis` (small multiples, 7.0), `storyboard`, `link` (crossfilter / linked views), `ink` (annotation authoring), `measure`, `context-menu`, `perspectives` (shareable views), `history` (undo/redo) and `highlight-filter` (`highlightFilter`, 7.9). Two chart types are premium: `unit` / `waffle`, and `raincloud` (7.1). These still function fully, but render an `APEXCHARTS` trial watermark until an entitled license is set via `ApexCharts.setLicense(key)` (static) or per-chart `chart.license`. They require a `premium` or `enterprise` plan; a `pro` key or the free tier keeps the watermark. Every other chart type and free module is never gated. Premium and Tier 2 are separate axes: since 8.0 every premium item is Tier 2, but not every Tier 2 item is premium (`renderer-canvas`, `drilldown`, `waterfall`, `dumbbell`, `streamgraph`, `sunburst`, `violin` and `icicle` are free and need an import). See the Licensing section in `references/feature-platform.md`.
73
+ > **Premium features and licensing.** Nine features are premium: `trellis` (small multiples, 7.0), `storyboard`, `link` (crossfilter / linked views), `ink` (annotation authoring), `measure`, `context-menu`, `perspectives` (shareable views), `history` (undo/redo) and `highlight-filter` (`highlightFilter`, 7.9). Two chart types are premium: `unit` / `waffle`, and `raincloud` (7.1). These still function fully, but render an `APEXCHARTS` trial watermark until an entitled license is set via `ApexCharts.setLicense(key)` (static) or per-chart `chart.license`. They require a `premium` or `enterprise` plan; a `pro` key or the free tier keeps the watermark. Every other chart type and free module is never gated. Premium and Tier 2 are separate axes: since 8.0 every premium item is Tier 2, but not every Tier 2 item is premium (`renderer-canvas`, `drilldown`, `radial-targets`, `waterfall`, `dumbbell`, `streamgraph`, `sunburst`, `violin` and `icicle` are free and need an import). See the Licensing section in `references/feature-platform.md`.
73
74
 
74
75
  ## 1. Critical Rules
75
76
 
@@ -79,22 +80,22 @@ metadata:
79
80
  4. **`yaxis` must be an array** when using multiple y-axes. Each entry needs a `seriesName` to map to the correct series.
80
81
  5. **`tooltip.shared` and `tooltip.intersect` are mutually exclusive.** `shared: true` shows all series at an x-position. `intersect: true` shows only the hovered point.
81
82
  6. **Use `null` (not `undefined` or empty string)** for missing data points. `undefined` is silently ignored and breaks the chart.
82
- 7. **`chart.stacked: true`** stacks `bar`, `area` and `line` series. In a mixed chart only the bar series stack by default (`chart.stackOnlyBar` defaults to `true`); set `stackOnlyBar: false` to stack its line and area series too. `waterfall`, `dumbbell` and `streamgraph` force it off, since they do their own accumulation.
83
+ 7. **`chart.stacked: true`** stacks `bar`, `area` and `line` series. In a mixed chart only the bar series stack by default (`chart.stackOnlyBar` defaults to `true`); set `stackOnlyBar: false` to stack its line and area series too. `waterfall`, `dumbbell` and `streamgraph` force it off, since they do their own accumulation. `chart.stackType: '100%'` draws each stack as shares of its total on a 0 to 100 axis; since v8.5 that holds for area and line stacks too (before, only bars drew percentages).
83
84
  8. **Responsive breakpoints** must be in ascending order in the `responsive` array.
84
85
  9. **For mixed/combo charts**, set `type` on each individual series object, not just on `chart.type`.
85
86
  10. **RadialBar values sit on the `plotOptions.radialBar.min` to `max` domain** (default 0 to 100, so percentages by default). Set `min` / `max` to plot raw values; a value outside the domain is clamped to the end of the arc.
86
87
  11. **Color hex values must include the `#` prefix** (e.g., `'#FF5733'`, not `'FF5733'`).
87
- 12. **The default `apexcharts` bundle is not everything (v8).** Next to `import ApexCharts from 'apexcharts'`, add `import 'apexcharts/unit'` (also for `waffle`), `'apexcharts/sunburst'`, `'apexcharts/violin'`, `'apexcharts/icicle'` or `'apexcharts/raincloud'` before writing that chart type. Add `import 'apexcharts/features/<name>'` before writing a `waterfall`, `dumbbell` or `streamgraph` chart, or using `drilldown`, `highlightFilter` (`highlight-filter`), `trellis`, `storyboard`, `perspectives`, `ink`, `renderer: 'canvas'` (`renderer-canvas`), `link`, `measure`, `history` or the context menu (`context-menu`). `import ApexCharts from 'apexcharts/full'` (script tag: `dist/apexcharts.full.min.js`) is the one entry that needs none of these. See the box above.
88
+ 12. **The default `apexcharts` bundle is not everything (v8).** Next to `import ApexCharts from 'apexcharts'`, add `import 'apexcharts/unit'` (also for `waffle`), `'apexcharts/sunburst'`, `'apexcharts/violin'`, `'apexcharts/icicle'` or `'apexcharts/raincloud'` before writing that chart type. Add `import 'apexcharts/features/<name>'` before writing a `waterfall`, `dumbbell` or `streamgraph` chart, or using `drilldown`, `highlightFilter` (`highlight-filter`), `plotOptions.radialBar.targets` (`radial-targets`, v8.5), `trellis`, `storyboard`, `perspectives`, `ink`, `renderer: 'canvas'` (`renderer-canvas`), `link`, `measure`, `history` or the context menu (`context-menu`). `import ApexCharts from 'apexcharts/full'` (script tag: `dist/apexcharts.full.min.js`) is the one entry that needs none of these. See the box above.
88
89
  13. **Tree-shaking**: importing `apexcharts/core` gives you a bare class, and you must also import chart-type entries and feature entries separately.
89
90
  14. **First-class aliases**: `funnel` and `pyramid` render through the bar engine; `gauge` renders through radialBar. Use them as `chart.type` directly (no `plotOptions.bar.isFunnel` needed). They are covered by the `apexcharts/bar` and `apexcharts/radialBar` tree-shaking entries respectively.
90
91
  15. **`violin` (statistical)** uses a per-point density profile: `data: [{ x, y: { density: [[value, weight], ...], points?: [number] } }]`, not a plain number. Since v6.9 a datum may instead supply only raw observations (`points: [number]`, no `y`) and the library derives the density via KDE (needs `apexcharts/features/stats` when tree-shaking).
91
- 16. **`render()` is idempotent**: calling `render()` twice on the same instance returns the same promise instead of building a duplicate chart. You still must `destroy()` before creating a *new* instance on the same element.
92
+ 16. **`render()` is idempotent**: calling `render()` twice on the same instance returns the same promise instead of building a duplicate chart. You still must `destroy()` before creating a *new* instance on the same element. Since v8.1 `render()` after `destroy()` draws that instance afresh, and `updateOptions` / `updateSeries` on a destroyed chart log a warning and resolve instead of throwing.
92
93
  17. **`histogram` (v6.9)** series carry **raw observations** (one number per event), not pre-aggregated counts; the chart chooses bin edges and counts them. Binning ships behind the stats feature: use the `apexcharts/histogram` entry, or `import 'apexcharts/features/stats'` alongside `apexcharts/bar` (the default `apexcharts` bundle already includes it).
93
94
  18. **`waterfall` (v7.1) accumulates for you.** The series carries the **deltas**, not the running total. A row that should show the running total carries `isSubtotal` or `isTotal` and **no `y`**; the library measures it. Do not pre-compute cumulative values.
94
95
  19. **`dumbbell` (v7.1) takes one series per measure**, each with the same `x` categories: `[{ name: '2020', data: [{ x, y }] }, { name: '2025', data: [{ x, y }] }]`. Do **not** zip the values into `y: [low, high]` pairs; that is the older `plotOptions.bar.isDumbbell` range-bar form, which still works but is a different chart.
95
96
  20. **`raincloud` (v7.1) takes the raw sample**, one datum per category: `data: [{ x, points: [number] }]`. It is a premium Tier 2 type, so it needs `import 'apexcharts/raincloud'` on top of the default bundle.
96
- 21. **Unknown names fail loudly (v7.9).** An unknown `chart.type` throws when the chart is constructed or updated, and the message names the closest real type (`'column'` is valid, a synonym for `'bar'`; `''` and `null` draw a line chart). An unknown top-level option key is kept but never read. Numeric-string axis bounds such as `yaxis.min: '10'` work, and a bound that cannot be parsed is ignored (the axis scales to the data). Both cases log a console warning, except in `apexcharts.min.js` and the CommonJS builds (the `*.common.js` files `require('apexcharts')` loads), which strip `console.warn`.
97
- 22. **A script tag names the exact version shown here**: `https://cdnjs.cloudflare.com/ajax/libs/apexcharts/8.2.0/apexcharts.min.js` or `https://cdn.jsdelivr.net/npm/apexcharts@8.2.0/dist/apexcharts.min.js`. Never write a 3.x or 4.x URL such as `.../apexcharts/3.54.1/...`: those are releases from 2024 and early 2025, and this skill does not describe them. If the environment only accepts an older release, use the newest one it accepts with the same major version as these URLs. See `references/framework-wrappers.md` for add-on files on each CDN.
97
+ 21. **Unknown names fail loudly (v7.9).** An unknown `chart.type` throws when the chart is constructed or updated, and the message names the closest real type (`'column'` is valid, a synonym for `'bar'`; `''` and `null` draw a line chart). An unknown top-level option key is kept but never read. Numeric-string axis bounds such as `yaxis.min: '10'` work, and a bound that cannot be parsed is ignored (the axis scales to the data). Both cases log a console warning, except in `apexcharts.min.js` (the minified script-tag file), which strips it. Since v8.1 the CommonJS builds (the `*.common.js` files `require('apexcharts')` loads) keep their warnings, and every build, `apexcharts.min.js` included, prints the warning that names a missing Tier 2 import.
98
+ 22. **A script tag names the exact version shown here**: `https://cdn.jsdelivr.net/npm/apexcharts@8.8.1/dist/apexcharts.min.js`. jsDelivr serves each release from npm as soon as it is published; cdnjs mirrors releases too but can lag by days, so use it only when the environment allows nothing else, with the newest version it lists. Never write a 3.x or 4.x URL such as `.../apexcharts/3.54.1/...`: those are releases from 2024 and early 2025, and this skill does not describe them. If the environment only accepts an older release, use the newest one it accepts with the same major version as these URLs. See `references/framework-wrappers.md` for add-on files on each CDN.
98
99
 
99
100
  ---
100
101
 
@@ -190,7 +191,7 @@ A branch may omit its own `y` and be the sum of its children *(fixed in v7.6 for
190
191
  # Default bundle (the standard chart types plus the Tier 1 features; see the box at the top)
191
192
  import ApexCharts from 'apexcharts'
192
193
 
193
- # Full bundle (v8.0): every chart type and feature, plus the unit-shapes and pictograms catalogs. No add-on needed.
194
+ # Full bundle (v8.0): every chart type and feature, plus the unit-shapes and pictograms catalogs. No add-on needed, except ignite-ui (in no bundle).
194
195
  import ApexCharts from 'apexcharts/full'
195
196
 
196
197
  # Bare core (no chart types, no optional features — must register manually)
@@ -252,6 +253,8 @@ import 'apexcharts/features/waterfall' # (v7.1) waterfall chart type (Tier
252
253
  import 'apexcharts/features/dumbbell' # (v7.1) dumbbell chart type (Tier 2 since v8)
253
254
  import 'apexcharts/features/streamgraph' # (v7.1) streamgraph chart type (Tier 2 since v8)
254
255
  import 'apexcharts/features/highlight-filter' # (v7.9) Part-of-whole highlight, highlightFilter (premium)
256
+ import 'apexcharts/features/radial-targets' # (v8.5) plotOptions.radialBar.targets on radialBar / gauge (free)
257
+ import 'apexcharts/features/ignite-ui' # (v8.8) Follow an Ignite UI theme on the page (no extra licence key). In NO bundle, not even full
255
258
  import 'apexcharts/features/trellis' # (v7.0) Small multiples (premium)
256
259
  import 'apexcharts/features/storyboard' # Scrollytelling (premium; registers perspectives)
257
260
  import 'apexcharts/features/perspectives' # Shareable view state (premium)
@@ -317,6 +320,8 @@ await chart.updateOptions({
317
320
  chart.destroy()
318
321
  ```
319
322
 
323
+ **Your options object is never written into (v8.1).** The constructor and every update copy what you pass, so after `updateOptions` / `updateSeries` your own object still holds what you wrote, not the merged result. Code that read the library's defaults or a later update back from it should read the live config from `chart.w.config` (not in the shipped types, so cast in TypeScript).
324
+
320
325
  ---
321
326
 
322
327
  ## 5. Formatter Function Signatures
@@ -326,18 +331,20 @@ chart.destroy()
326
331
  | `xaxis.labels.formatter` | `(value: string \| number, timestamp?: number, opts?) => string` | Formatted x-axis tick label |
327
332
  | `yaxis.labels.formatter` | `(value: number, opts?) => string` | Formatted y-axis tick label |
328
333
  | `tooltip.x.formatter` | `(value: number, opts?) => string` | Tooltip x-value text |
329
- | `tooltip.y.formatter` | `(value: number \| null, opts?) => string` | Tooltip y-value text. `value` is `null` at a gap, so guard before a number method: `(val) => val == null ? 'n/a' : val.toFixed(2)` |
334
+ | `tooltip.y.formatter` | `(value: number \| null, opts?) => string \| null \| undefined` | Tooltip y-value text. `value` is `null` at a gap, so guard before a number method: `(val) => val == null ? 'n/a' : val.toFixed(2)`. In a shared tooltip, returning `null` or `undefined` hides that series' row (typed since v8.2) |
330
335
  | `tooltip.y.title.formatter` | `(seriesName: string, opts?) => string` | Tooltip series title |
331
336
  | `tooltip.z.formatter` | `(value: number) => string` | Tooltip z-value (bubble) |
332
337
  | `dataLabels.formatter` | `(value: number \| string \| number[], opts?) => string \| number` | Data label text |
333
- | `legend.formatter` | `(legendName: string, opts?) => string` | Legend item text |
338
+ | `legend.formatter` | `(legendName: string, opts?) => string` | Legend item HTML. `legendName` is the raw, unescaped name |
334
339
  | `plotOptions.pie.donut.labels.value.formatter` | `(val: string) => string` | Donut center value |
335
340
  | `plotOptions.pie.donut.labels.total.formatter` | `(w: { globals, config }) => string` | Donut center total |
336
341
  | `plotOptions.radialBar.dataLabels.value.formatter` | `(val: number) => string` | RadialBar center value |
337
342
 
338
- **Important:** All formatters must return a `string` (or `number` for `dataLabels.formatter`). Never return `undefined`.
343
+ **Important:** All formatters must return a `string` (or `number` for `dataLabels.formatter`). Never return `undefined`, except from `tooltip.y.formatter` in a shared tooltip, where `null` or `undefined` deliberately hides that row.
344
+
345
+ **Names are text, formatter output is HTML (v8.3.1, v8.4).** Series names, categories, goal names and treemap / sunburst / icicle node names are escaped in the legend and tooltip (and in `renderToHTML` output), so markup inside them shows literally. To style a name, return the markup from `legend.formatter` or a tooltip formatter: a result that differs from the name is written as HTML, one that hands the name back unchanged is shown as text. Those formatters receive the raw name, so escape it yourself (`&` and `<`) before wrapping it in markup when names come from user data.
339
346
 
340
- **Per-point data label offsets (v6.8):** `dataLabels.offsetX` and `dataLabels.offsetY` accept `number | ((opts) => number)`. The function receives `{ series, seriesIndex, dataPointIndex, w }` (same signature as `dataLabels.style.colors` functions). Use it for deliberate placement; keep it pure, since it may be called more than once per label. Collisions do not need it: since v7.8 `dataLabels.avoidOverlap` (on by default) nudges labels that land on each other apart along the value axis, across series as well as within one, after the offsets are applied (radial types keep their own placement). Tune it with `{ gap, maxShift, hide }`, or set `avoidOverlap: false` to keep each label exactly at its mark and offset.
347
+ **Per-point data label offsets (v6.8):** `dataLabels.offsetX` and `dataLabels.offsetY` accept `number | ((opts) => number)`. The function receives `{ series, seriesIndex, dataPointIndex, w }` (same signature as `dataLabels.style.colors` functions). Use it for deliberate placement; keep it pure, since it may be called more than once per label. Collisions do not need it: since v7.8 `dataLabels.avoidOverlap` (on by default) nudges labels that land on each other apart along the value axis, across series as well as within one, after the offsets are applied (radial types keep their own placement). Tune it with `{ gap, maxShift, hide, hideOrder }`, or set `avoidOverlap: false` to keep each label exactly at its mark and offset. *(v8.5)* `maxShift: 0` never moves a label, and `hideOrder: 'balanced'` spreads the labels `hide` drops across the series instead of emptying the later-drawn one (default `'later'`). On a line or area chart, where a moved label sits beside the wrong value, prefer `{ maxShift: 0, hide: true, hideOrder: 'balanced' }`.
341
348
 
342
349
  ---
343
350
 
@@ -431,7 +438,7 @@ Also: do NOT use `xaxis.categories` when your data already has `{ x, y }` format
431
438
 
432
439
  ### Pitfall 6: tooltip.shared vs tooltip.intersect
433
440
 
434
- ❌ **WRONG** — both enabled (conflicting):
441
+ ❌ **WRONG**: both enabled (conflicting; constructing the chart throws, and an `updateOptions` that sets both logs a warning):
435
442
  ```js
436
443
  { tooltip: { shared: true, intersect: true } }
437
444
  ```
@@ -441,10 +448,13 @@ Also: do NOT use `xaxis.categories` when your data already has `{ x, y }` format
441
448
  // Mode A: Show all series values at x-position (default for line/area)
442
449
  { tooltip: { shared: true, intersect: false } }
443
450
 
444
- // Mode B: Show only hovered data point (better for scatter)
451
+ // Mode B: Show only hovered data point (better for scatter). Since v8.7, where
452
+ // several series' markers are drawn at the hovered spot, it lists one row per series.
445
453
  { tooltip: { shared: false, intersect: true } }
446
454
  ```
447
455
 
456
+ **Hover without the tooltip box *(v8.5)***: `tooltip.visible: false` keeps everything a hover resolves (the `mouseMove` / `click` / data point events still report the point, crosshairs and hover markers still follow their own options) and draws no tooltip box, for an app that shows hover details in its own UI. `tooltip.enabled: false` turns hover handling off entirely.
457
+
448
458
  **Reaching content inside a `custom` tooltip *(v7.6)***: a tooltip closes as the pointer leaves the data point, so a link or button returned by `custom` can never be clicked. `tooltip.interactive: true` holds it open while the pointer is over it. It is off by default, and while it is on `followCursor` is **ignored** (a tooltip that trails the cursor retreats from every approach); the configured `followCursor` value is left alone and applies again the moment `interactive` goes back off.
449
459
 
450
460
  ```js
@@ -595,7 +605,7 @@ The console names the import in every case (since 7.9.1 the minified bundle prin
595
605
 
596
606
  - **A Tier 2 chart type** (`unit`, `waffle`, `sunburst`, `violin`, `icicle`, and `raincloud`, which draws through violin): `render()` rejects and nothing draws. An `updateOptions`, `updateSeries` or `appendSeries` that asks for one is refused, and the chart stays as it was.
597
607
  - **`waterfall`, `dumbbell` or `streamgraph`** without its feature (or a `raincloud` on a page that has violin but not the raincloud feature): one warning and an empty plot.
598
- - **A Tier 2 feature** (`drilldown`, `highlightFilter`, `trellis`, `storyboard`, `perspectives`, `ink`, `renderer: 'canvas'`, `link`, `measure`, `history`, `contextMenu`): the chart draws without it, with a warning when its config is present. A trellis renders as one plain chart; a drilldown chart draws its root level and never navigates, and `chart.drillDown()` throws.
608
+ - **A Tier 2 feature** (`drilldown`, `highlightFilter`, `plotOptions.radialBar.targets`, `trellis`, `storyboard`, `perspectives`, `ink`, `renderer: 'canvas'`, `link`, `measure`, `history`, `contextMenu`): the chart draws without it, with a warning when its config is present. A trellis renders as one plain chart; a drilldown chart draws its root level and never navigates, and `chart.drillDown()` throws; a radialBar or gauge draws its dial without the targets.
599
609
 
600
610
  Or start from `import ApexCharts from 'apexcharts/full'`, which needs none of these.
601
611
 
@@ -634,6 +644,25 @@ await chart.appendData([{ data: [newPoint] }])
634
644
  await chart.updateOptions({ title: { text: 'New Title' } })
635
645
  ```
636
646
 
647
+ ### Pitfall 17: Ignite UI theme on the page, but the chart ignores it *(from apexcharts 8.8.0)*
648
+
649
+ Ignite UI theming is an opt-in add-on. Without it the page's `--ig-*` tokens are ignored, with no error and no warning, and `theme.designSystem` does nothing. It is in no bundle, `apexcharts/full` included.
650
+
651
+ ❌ **WRONG**: Ignite UI stylesheet loaded, no add-on, and a pinned mode:
652
+ ```js
653
+ import ApexCharts from 'apexcharts'
654
+ new ApexCharts(el, { theme: { mode: 'light' }, series }).render() // stays light under a dark Ignite UI theme
655
+ ```
656
+
657
+ ✅ **CORRECT**: import the add-on once, before the first render, and leave `theme.mode` unset so the theme's dark variant (`--ig-theme-variant`) can pick the mode:
658
+ ```js
659
+ import ApexCharts from 'apexcharts'
660
+ import 'apexcharts/features/ignite-ui' // no extra licence key
661
+ new ApexCharts(el, { series }).render()
662
+ ```
663
+
664
+ Script tags: `dist/features/ignite-ui.js` after `dist/apexcharts.js`. A chart rendered before the add-on loaded picks it up on its next update, resize or `chart.refreshTokens()`. Anything you set outranks the theme (see "Ignite UI add-on" in `references/feature-platform.md`).
665
+
637
666
  ---
638
667
 
639
668
  ## 7. API Methods Quick Reference
@@ -664,6 +693,7 @@ await chart.updateOptions({ title: { text: 'New Title' } })
664
693
  | `setLocale(localeName)` | Switch locale. |
665
694
  | `toggleDataPointSelection(seriesIndex, dataPointIndex?)` | Select/deselect data point. |
666
695
  | `rowSeries(opts?)` | *(v6.9)* Returns the raw rows behind this chart's marks as a unit-chart series (one cluster per mark), or `null` when the type has no row source (works for histogram / boxPlot / violin, needs `apexcharts/features/stats`). `opts.maxRows` caps the output (default 3000). Drawing the result needs the `unit` type, Tier 2 since v8 (`import 'apexcharts/unit'`). |
696
+ | `getRadialScales()` | *(v8.5)* Where a radialBar or gauge drew its dial on the last render: `{ cx, cy, startAngle, endAngle, min, max, radius, thickness, rings, bands, hollow, needle, angle(v), point(v, r?) }`, in the px of `getChartArea()`. `null` on other types and before the first render. Core, no import. |
667
697
  | `getState()` | Returns snapshot of chart state. |
668
698
  | `addEventListener(name, handler)` | Subscribe to chart event. |
669
699
  | `removeEventListener(name, handler)` | Unsubscribe from chart event. |
@@ -677,7 +707,7 @@ await chart.updateOptions({ title: { text: 'New Title' } })
677
707
  | `chart.history.undo() / redo() / jump(id) / transaction(fn)` | history | Undo/redo over the command journal. |
678
708
  | `chart.perspectives.capture() / toURL() / apply(token)` | perspectives | Serialize / restore the exact view. |
679
709
  | `chart.getActiveRenderer()` | renderer-canvas | Returns `'svg' \| 'canvas'` currently in use. |
680
- | `chart.refreshTokens()` | facet | Re-read `--apx-*` CSS custom properties. |
710
+ | `chart.refreshTokens()` | facet | Re-read `--apx-*` CSS custom properties (and, with the `ignite-ui` add-on, the page's `--ig-*` tokens). Call it after a stylesheet swap that does not trigger a render, such as an Ignite UI light/dark switch. |
681
711
  | `chart.startMeasure() / stopMeasure() / clearMeasures()` | measure | Drive the measure ruler from code. |
682
712
  | `chart.storyboard.bind({ beats }) / goTo() / unbind()` | storyboard | Scroll-driven choreography. |
683
713
  | `chart.drillDown(id) / drillUp() / drillToRoot()` | drilldown | Navigate the drill-down hierarchy. |
@@ -736,6 +766,12 @@ await chart.updateOptions({ title: { text: 'New Title' } })
736
766
  markerClick: (event, chart, options) => {},
737
767
  xAxisLabelClick: (event, chart, options) => {},
738
768
 
769
+ // (v8.7) On a marker (line, area, scatter, bubble, radar), markerClick, dataPointSelection
770
+ // and the SVG renderer's click carry options.coincident (ApexCoincidentPoint[]: { seriesIndex, dataPointIndex })
771
+ // for every visible series whose marker is drawn at that spot. options.seriesIndex /
772
+ // dataPointIndex still name the marker on top. The canvas renderer's click has no
773
+ // coincident; use markerClick there.
774
+
739
775
  // Data point events
740
776
  dataPointSelection: (event, chart, options) => {},
741
777
  dataPointMouseEnter: (event, chart, options) => {},
@@ -773,9 +809,10 @@ Every feature below is off by default in config terms. The **Tier** column is ab
773
809
 
774
810
  | Feature | Tier | Import | One-liner |
775
811
  |---|---|---|---|
776
- | **Weave** (plugins) | 1 | `apexcharts/features/weave` | Publish reusable chart plugins against a stable `ApexCharts.registerPlugin({ name, setup })` API; activate per chart with `plugins: [{ name }]`. Contract is at **v6** (v7.5): `info`/`categories`/`markDerived` (v2), `reserve` (v3), `pointer` (v4), `claim`/`drawn`/`declare`/`can` (v6). Declare the **lowest** `apiVersion` you can run on and feature-detect the rest: a host older than the version you declare skips your plugin outright. |
812
+ | **Weave** (plugins) | 1 | `apexcharts/features/weave` | Publish reusable chart plugins against a stable `ApexCharts.registerPlugin({ name, setup })` API; activate per chart with `plugins: [{ name }]`. Contract is at **v7** (v8.1): `info`/`categories`/`markDerived` (v2), `reserve` (v3), `pointer` (v4), `claim`/`drawn`/`declare`/`can` (v6), `highlight()` (v7), and the capabilities `observations` and `scale-orientation` (8.0.1) and `radial-scales` (8.5). Declare the **lowest** `apiVersion` you can run on and feature-detect the rest: a host older than the version you declare skips your plugin outright. |
777
813
  | **Marks** (custom series) | 1 | `apexcharts/features/marks` | `ApexCharts.registerSeriesType(name, { renderItem })` for first-class custom marks (lollipop, bullet). Baseline is `scales.y(0)`, **not** `api.zeroY`. |
778
814
  | **Facet** (themes/tokens) | 1 | `apexcharts/features/facet` | `theme: { follow: 'os', name }`, `--apx-*` CSS custom props, `ApexCharts.registerTheme`. |
815
+ | **Ignite UI theming** | add-on | `apexcharts/features/ignite-ui` | *(from 8.8.0, no extra licence key, not a premium feature)* Charts follow an Ignite UI theme on the page: series colours, text, grid, tooltips, menus, font, and light or dark from `--ig-theme-variant` when `theme.mode` is unset. In no bundle, `full` included; script tag `dist/features/ignite-ui.js` after `apexcharts.js`. Ranks below everything you set; `theme: { designSystem: false }` turns it off per chart. |
779
816
  | **Morph** | 1 | `apexcharts/features/morph` | Animated transitions between chart types. |
780
817
  | **Stats** | 1 | `apexcharts/features/stats` | *(v6.9)* Statistics behind histogram binning, boxPlot/violin raw-sample summaries (R type 7 quartiles, KDE), and `chart.rowSeries()`. The `apexcharts/histogram` entry includes it. |
781
818
  | **Cadence** (easing) | core | none | `chart.animations.easing` accepts a named curve, cubic-bezier array, or function; `ApexCharts.registerEasing`. |
@@ -784,6 +821,7 @@ Every feature below is off by default in config terms. The **Tier** column is ab
784
821
  | **Marker batching** | core | none | *(v7.0)* `markers: { largeDatasetThreshold: n }`. Above `n` points, a series' markers are drawn as one path per marker size instead of one element per point. **Opt-in, default `0` (off)**, because merged marker paths are not pixel-identical: overlapping markers lose their individual outlines and dense clusters read flatter. Also covers the markers `showNullDataPoints` adds, which is what makes a null-heavy series slow even at `size: 0`. |
785
822
  | **Drilldown** | **2** | `apexcharts/features/drilldown` | *(Tier 2 since v8.0)* `drilldown: { enabled, series }` + a `drilldown` id on data points; `chart.drillDown()/drillUp()`. v6.9 adds line/area support, async levels (`onDrillDown` may return a Promise), a loading overlay, and the `drillDownError` event. |
786
823
  | **Highlight filter** | **2** | `apexcharts/features/highlight-filter` | *(v7.9, premium)* `highlightFilter` draws each value faded with a part of it solid in front, from the same baseline. The part travels with the data: `series[].highlightData` (parallel to `data`) or `{ x, y, highlight }` per point, `highlightFilter.data` on pie / donut / polarArea / radialBar; `chart.highlightFilter.set(parts)` / `clear()`. Bar, column, funnel, line, area, pie, donut, polarArea, radialBar (and gauge), treemap. See "Highlight filter" in `references/feature-platform.md`. |
824
+ | **Radial targets** | **2** | `apexcharts/features/radial-targets` | *(v8.5, free)* `plotOptions.radialBar.targets: [{ value, seriesIndex?, shape?, position?, label? }]` marks a target or limit on a radialBar ring or a gauge (`value: 'series'` follows the ring's own value). Without the import the dial draws without them and the console warns once. See `references/circular-charts.md`. |
787
825
  | **Trellis** (small multiples) | **2** | `apexcharts/features/trellis` | *(v7.0, premium)* `trellis: { by: 'region', minPanelWidth }` splits the series into a grid of real charts sharing one scale, legend, toolbar and crosshair. Also `row` × `column` for 2-D grids. |
788
826
  | **Strata** (canvas) | **2** | `apexcharts/features/renderer-canvas` | `chart: { renderer: 'auto', rendererThreshold }` paints the dense series layer to canvas while axes/tooltips/exports stay SVG. Falls back to SVG if the module is missing. |
789
827
  | **Rewind** (undo/redo) | **2** | `apexcharts/features/history` | *(premium)* `chart: { history: { enabled: true } }`, then `chart.history.undo()/redo()/jump()/transaction()`. |
@@ -806,7 +844,7 @@ For detailed chart-family-specific options, data format variants, and full worki
806
844
  | Pie, Donut, Polar Area, Radial Bar, Gauge, Sunburst, Unit, Waffle, Pictograms | `references/circular-charts.md` |
807
845
  | Heatmap (incl. cell shapes), Treemap, Icicle | `references/grid-charts.md` |
808
846
  | Radar | `references/radar-charts.md` |
809
- | Feature platform (small multiples, plugins, canvas, undo/redo, themes, crossfilter, storyboard, ...) | `references/feature-platform.md` |
847
+ | Feature platform (small multiples, plugins, canvas, undo/redo, themes, `--apx-*` tokens, Ignite UI theming, crossfilter, storyboard, ...) | `references/feature-platform.md` |
810
848
  | Bundle tiers, Tree-shaking, Bundle optimization | `references/tree-shaking.md` |
811
849
  | Server-side rendering, Hydration | `references/ssr.md` |
812
850
  | React, Vue, Angular integration | `references/framework-wrappers.md` |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "apexcharts-skill",
3
- "version": "4.0.2",
4
- "description": "AI coding skill for ApexCharts.js — structured reference docs that help AI assistants (Claude, Cursor, Copilot, etc.) generate correct ApexCharts code.",
3
+ "version": "4.2.0",
4
+ "description": "AI coding skill for ApexCharts.js: structured reference docs that help AI assistants (Claude, Cursor, Copilot, etc.) generate correct ApexCharts code.",
5
5
  "keywords": [
6
6
  "apexcharts",
7
7
  "ai",
@@ -72,8 +72,7 @@ import ApexCharts from 'apexcharts/dumbbell' // == apexcharts/bar + features/d
72
72
 
73
73
  ```js
74
74
  {
75
- chart: { type: 'bar', height: 350, stacked: true },
76
- // stackType: '100%' // uncomment for percentage stacking
75
+ chart: { type: 'bar', height: 350, stacked: true }, // add stackType: '100%' to chart for percentage stacking
77
76
  series: [
78
77
  { name: 'Product A', data: [44, 55, 41] },
79
78
  { name: 'Product B', data: [13, 23, 20] },
@@ -84,6 +83,8 @@ import ApexCharts from 'apexcharts/dumbbell' // == apexcharts/bar + features/d
84
83
  }
85
84
  ```
86
85
 
86
+ `chart.stackType: '100%'` draws each stack as shares of its total on a 0 to 100 axis, and labels read as percentages; the tooltip keeps the raw value. Since v8.5 the same holds for stacked area and line series (before, they drew raw values on the 0 to 100 axis). In a combo, a line or area joins the percent stack only with `chart.stackOnlyBar: false`.
87
+
87
88
  ### Range Bar (start/end values)
88
89
 
89
90
  ```js
@@ -101,6 +102,8 @@ import ApexCharts from 'apexcharts/dumbbell' // == apexcharts/bar + features/d
101
102
  }
102
103
  ```
103
104
 
105
+ Data labels are off by default on a range bar, and once enabled the default prints `end - start`. A `dataLabels.formatter` of your own receives the value as `[start, end]`, on vertical range columns as well since v8.2 (before, those passed only the end): `` formatter: ([start, end]) => `${start} to ${end}` ``.
106
+
104
107
  ### Timeline / Gantt Chart (Range Bar with dates)
105
108
 
106
109
  ```js
@@ -341,7 +344,7 @@ A stack of a single data point also stopped rounding its baseline in v7.4, which
341
344
  dataLabels: { animate: { enabled: false } }
342
345
  ```
343
346
 
344
- **⚠️ `dataLabels.avoidOverlap` is on by default (v7.8).** Labels that land on each other, across series too, are nudged apart along the value axis (left and right on a horizontal bar), each by at most about its own size. A pair that cannot be separated stays overlapping unless you pass `{ hide: true }`. Tune it with `{ gap, maxShift, hide }`, or set `false` to keep every label where it was placed. Rotated labels (`orientation: 'vertical'`) are never moved. A manual `offsetY` that only separated labels may no longer be needed.
347
+ **⚠️ `dataLabels.avoidOverlap` is on by default (v7.8).** Labels that land on each other, across series too, are nudged apart along the value axis (left and right on a horizontal bar), each by at most about its own size. A pair that cannot be separated stays overlapping unless you pass `{ hide: true }`. Tune it with `{ gap, maxShift, hide }`, or set `false` to keep every label where it was placed. Rotated labels (`orientation: 'vertical'`) are never moved. A manual `offsetY` that only separated labels may no longer be needed. *(v8.5)* `maxShift: 0` never moves a label, and `hideOrder: 'balanced'` makes `hide` drop labels evenly across the series rather than always the later-drawn one (default `'later'`).
345
348
 
346
349
  ### Bar Chart Race (v6.4)
347
350
 
@@ -448,3 +451,4 @@ Bar, column, funnel and pyramid charts take `highlightFilter`, which draws each
448
451
  11. **Assuming `borderRadiusWhenStacked` is still removed**: it was dead config in v7.0 through v7.3 and is a working option again from v7.4 (`'all'` default, `'last'` to leave the baseline square). Guidance written for v7.0 says to delete it; on v7.4+ that silently reverts a deliberate `'last'` to `'all'`.
449
452
  12. **Expecting data labels to snap on update** *(v7.0)*: `dataLabels.animate.enabled` now defaults to `true` on bar/column. Set it to `false` for the old behavior.
450
453
  13. **Waterfall or dumbbell on the default bundle** *(v8.0)*: draws an empty plot plus one console warning. Add `import 'apexcharts/features/waterfall'` (or `'apexcharts/features/dumbbell'`) next to `import ApexCharts from 'apexcharts'`.
454
+ 14. **Expecting every category name on a dense horizontal bar chart** *(v8.5)*: names that would overlap are thinned (the top one always stays, the rest evenly spaced; the tooltip and keyboard navigation keep every name). `xaxis.labels.hideOverlappingLabels: false` draws them all, and so does setting a `yaxis.labels.formatter`.
@@ -79,6 +79,8 @@ Use `null` to create gaps in the line:
79
79
  series: [{ data: [10, 25, null, null, 50, 60] }]
80
80
  ```
81
81
 
82
+ In `{ x, y }` data write a gap as `{ x, y: null }`, which keeps its category label. Since v8.1 a bare `null` entry in `{ x, y }` or `[x, y]` data also draws as a gap instead of throwing, but it blanks the category label at that slot, and one among the first three points logs a "mixed formats" console warning.
83
+
82
84
  ### Scatter Chart
83
85
 
84
86
  Always use XY format:
@@ -202,6 +204,17 @@ stroke: {
202
204
  }
203
205
  ```
204
206
 
207
+ **Dash patterns (v8.5).** Every dash option (`stroke.dashArray`, `markers.strokeDashArray`, `grid.strokeDashArray`, annotation `strokeDashArray`, `forecastDataPoints.dashArray`, crosshair strokes) takes a number (dash and gap of that length), a pattern string (`'8 3 2 3'` or `'8,3,2,3'`) or an array of lengths (type `ApexDashPattern`). On the per-series options a **top-level array is one value per series**, so:
208
+
209
+ ```js
210
+ stroke: { dashArray: '8 3 2 3' } // dash-dot on every series
211
+ stroke: { dashArray: [0, '8 3 2 3'] } // first solid, second dash-dot
212
+ stroke: { dashArray: [8, 3, 2, 3] } // NOT a pattern: four series dashed 8, 3, 2 and 3
213
+ stroke: { dashArray: [0, [8, 3, 2, 3]] } // a nested array is a pattern for one series
214
+ ```
215
+
216
+ Dotted lines are a zero-length dash with a round cap: `dashArray: '0 6'` with `stroke.lineCap: 'round'`. X and y axis annotations take `strokeLineCap: 'butt' | 'square' | 'round'` *(v8.5, default `'butt'`)* for the same effect on their lines and range borders.
217
+
205
218
  ### Markers
206
219
 
207
220
  ```js
@@ -256,6 +269,22 @@ xaxis: {
256
269
  }
257
270
  ```
258
271
 
272
+ ### Mouse-wheel zoom is cooperative (v8.3)
273
+
274
+ With `chart.zoom.enabled` and the default `allowMouseWheelZoom: 'auto'` (offered only where the toolbar reset button is present), a bare wheel over the chart scrolls the page and briefly shows a hint; **Ctrl/Cmd + wheel**, or a trackpad pinch, zooms. Charts written for the pre-8.3 wheel no longer zoom on a plain scroll.
275
+
276
+ ```js
277
+ chart: {
278
+ zoom: {
279
+ enabled: true,
280
+ allowMouseWheelZoom: true, // every wheel zooms again (even with the toolbar hidden)
281
+ wheelHint: false, // or keep 'auto' and hide the hint
282
+ },
283
+ }
284
+ ```
285
+
286
+ The hint text is the locale's `toolbar.wheelZoomHint` (`chart.locales[].options.toolbar.wheelZoomHint`, default `'Use {key} + scroll to zoom'`, `{key}` becomes Ctrl or ⌘), translated in every shipped locale.
287
+
259
288
  ### A way out of a zoom when the toolbar is hidden (v7.4)
260
289
 
261
290
  Hiding the toolbar does not disable drag-to-zoom (a drag is a deliberate gesture, unlike the wheel and the pinch), so a viewer can zoom a bare chart and then have nothing on screen that puts the range back.
@@ -34,7 +34,7 @@ import { person, registerMarks } from 'apexcharts/pictograms'
34
34
  // Pictogram glyph collection (v7.0), one drawn mark per unit. See "Pictograms" below.
35
35
  ```
36
36
 
37
- **⚠️ Sunburst and unit / waffle are Tier 2 since v8.0.** Pie, donut, polarArea, radialBar and gauge are in the default `apexcharts` bundle; `sunburst` and `unit` (with the `waffle` alias and the beeswarm layout) are not. Add `import 'apexcharts/sunburst'` or `import 'apexcharts/unit'` next to `import ApexCharts from 'apexcharts'` (script tag: `dist/sunburst.js` or `dist/unit.js`), or use the full bundle (`apexcharts/full`, `dist/apexcharts.full.min.js`). Without it the chart draws nothing and the console says the type is not registered, naming the import.
37
+ **⚠️ Sunburst and unit / waffle are Tier 2 since v8.0.** Pie, donut, polarArea, radialBar and gauge are in the default `apexcharts` bundle; `sunburst` and `unit` (with the `waffle` alias and the beeswarm layout) are not. Add `import 'apexcharts/sunburst'` or `import 'apexcharts/unit'` next to `import ApexCharts from 'apexcharts'` (script tag: `dist/sunburst.js` or `dist/unit.js`), or use the full bundle (`apexcharts/full`, `dist/apexcharts.full.min.js`). Without it the chart draws nothing and the console says the type is not registered, naming the import. `plotOptions.radialBar.targets` (v8.5) is a Tier 2 feature as well: `import 'apexcharts/features/radial-targets'` (see "Targets" below).
38
38
 
39
39
  ---
40
40
 
@@ -93,7 +93,7 @@ A gauge is a single-value `radialBar` alias. Series is a flat one-element array;
93
93
  { from: 30, to: 70, color: '#FEB019' },
94
94
  { from: 70, to: 100, color: '#00E396' }
95
95
  ],
96
- bandsStyle: { strokeWidth: '50%', gap: 1 },
96
+ bandsStyle: { strokeWidth: '50%', gap: 2 }, // gap: px along the band (v8.1); '1%' of the scale or '1.5deg' (v8.5) look the same at every size
97
97
  ticks: {
98
98
  show: true,
99
99
  major: { count: 11, length: 8, width: 2, color: '#334155', placement: 'outside' },
@@ -110,6 +110,53 @@ A gauge is a single-value `radialBar` alias. Series is a flat one-element array;
110
110
 
111
111
  A plain radialBar is effectively a gauge with `shape: 'arc'`. A semi-circle gauge is `startAngle: -90, endAngle: 90`.
112
112
 
113
+ **Band gaps (v8.1, v8.5):** `bandsStyle.gap` is measured in px along the band since 8.1, as documented; before that it was applied in value units, so a gap tuned on an older release may need raising. A number or `'4px'` is px, so it takes a smaller angle on a larger gauge; `'1%'` (a share of the `min..max` scale) and `'1.5deg'` look the same at every size. A band narrower than its gap is not drawn, and the console says which. Default `0`.
114
+
115
+ **Centre value label:** the default radialBar and gauge value and total formatters append `%` only on the default 0 to 100 domain *(v8.1)*; with a custom `min` / `max` (a speedometer) they print the bare value.
116
+
117
+ #### Targets (v8.5, add-on)
118
+
119
+ `plotOptions.radialBar.targets` puts marks at a value on a ring: a target, a limit, last period's reading. It needs `import 'apexcharts/features/radial-targets'` (script tag `dist/features/radial-targets.js`, or the full bundle): the add-on is free but not in the default bundle, and without it the dial draws without the targets and the console warns once.
120
+
121
+ ```js
122
+ import ApexCharts from 'apexcharts'
123
+ import 'apexcharts/features/radial-targets' // Tier 2: not in the default bundle
124
+
125
+ {
126
+ chart: { type: 'gauge', height: 360 },
127
+ series: [62],
128
+ labels: ['Uptime'],
129
+ plotOptions: {
130
+ radialBar: {
131
+ min: 0, max: 100,
132
+ targets: [
133
+ { value: 80, label: { text: 'Goal' } }, // a line across the ring
134
+ { value: 'series', shape: 'triangle', position: 'outside' }, // a pointer that follows the value
135
+ { value: 95, seriesIndex: 0, shape: 'circle', color: '#FF4560', id: 'limit' },
136
+ ],
137
+ },
138
+ },
139
+ }
140
+ ```
141
+
142
+ Each entry (`ApexRadialTarget`):
143
+
144
+ | Key | Default | Notes |
145
+ |---|---|---|
146
+ | `value` | required | A number in the `min..max` domain (clamped to it), or `'series'` to follow the ring's own value. A missing or non-numeric value draws nothing. |
147
+ | `seriesIndex` | `0` | The ring it marks. |
148
+ | `shape` | `'line'` | `'line'`, `'triangle'` (points at the ring) or `'circle'`. |
149
+ | `position` | `'across'` (`'outside'` for a triangle) | Across the ring's centre line, or off its outer or inner edge (`'inside'`). |
150
+ | `length` | `'130%'` for a line, `10` otherwise | Along the radius: px, or a percentage of the ring's thickness. |
151
+ | `width` | `3` for a line, `12` for a triangle | Across the radius, in px. Not used by a circle. |
152
+ | `color` / `strokeColor` / `strokeWidth` | `chart.foreColor` / none / `0` | The outline reads a mark over a band of its own colour. |
153
+ | `label` | none | `{ text, offset (4), style: { fontSize, fontFamily, fontWeight, color } }`, drawn upright off the mark's outer end (inner end for `'inside'`). |
154
+ | `cssClass`, `id` | none | `id` keeps a target's identity across updates, so a reordered list moves rather than swaps. |
155
+
156
+ Targets sit over the rings and bands, sweep in with their ring on mount, move from the old value on an update (`updateOptions` changes them), and hide with a legend-hidden ring.
157
+
158
+ **Reading the dial (v8.5, core):** `chart.getRadialScales()` returns where the last render drew it: `{ cx, cy, startAngle, endAngle, min, max, outerRadius, radius, thickness, rings: [{ seriesIndex, radius, thickness, trackThickness }], bands, hollow, needle, angle(value), point(value, radius?) }`, in the px of `chart.getChartArea()`, angles in degrees clockwise from 12 o'clock. It is frozen and replaced on every render, so read it again after an update or resize. `null` on other chart types and before the first render. A Weave plugin gets the same object as `api.radialScales`.
159
+
113
160
  **Needle value label (v7.9):** on a `gauge` with `shape: 'needle'` and no `plotOptions.radialBar.dataLabels.value.offsetY`, the value is placed below the farthest reach of the needle, so the two never cross (it used to sit under the needle). Set `offsetY` to place it yourself.
114
161
 
115
162
  ### Sunburst (v6.7)
@@ -159,6 +206,8 @@ import 'apexcharts/sunburst' // Tier 2 since v8.0: not in the default bundle
159
206
 
160
207
  Colours, `stroke`, `legend`, and `title` behave as they do on pie and donut. A sunburst can also adapt an existing `drilldown` config instead of a native `children` hierarchy.
161
208
 
209
+ **`tooltip.custom` on a sunburst (v8.4)** runs once per hovered node with `{ seriesIndex: 0, dataPointIndex: -1, node, percentOfParent, percentOfTotal, series, w, ctx }` (`node` carries `name`, `value` and, on a branch, `children`; the percentages are 0 to 100 with one decimal). Return markup or an Element to replace the tooltip, or `null` / `undefined` to keep the built-in row. A custom written for axis data points must return `null` when `node` is set. The icicle and nested-treemap branches are called the same way (see `references/grid-charts.md`).
210
+
162
211
  A branch may **omit its own `y`** and be the sum of its children. That is the documented shape, but it only began working in v7.6: before that the non-axis parser required every datum to carry `x` and `y`, so a branch with only `children` was dropped, the series came back empty, and the chart drew nothing while warning about pie data. The samples all gave their top-level nodes a `y`, which is what hid it from the moment sunburst shipped.
163
212
 
164
213
  **The same tree in cartesian coordinates** is the `icicle` type *(v7.6)*: one band per depth level instead of concentric rings, labels horizontal at every depth, and `direction: 'up'` for flame graphs. It is an opt-in import. See `references/grid-charts.md`.
@@ -194,6 +243,8 @@ import 'apexcharts/unit' // Tier 2 since v8.0: not in the default bundle
194
243
 
195
244
  **Motion (v6.9):** marks travel on a damped spring by default, so an update landing mid-flight retargets with the marks' velocity instead of restarting them (a dragged slider reads as continuous motion, not stutter). Configure via `plotOptions.unit.gather`: `motion: 'auto' | 'spring' | 'tween'`, `spring: 'crisp' | 'gentle' | 'snappy'`, `easing: 'outCubic' | 'inOutCubic' | 'outBack'` (setting `easing` implies tween), and `enter: 'burst' | 'fade' | 'rise'`.
196
245
 
246
+ **Update timing (v8.6):** a unit update follows `chart.animations.dynamicAnimation` like every other type: 350 ms by default (it was 800 ms before 8.6, ignoring that option), the springs and stagger scaled to it, and no tween at all when `dynamicAnimation.enabled` is `false`. Set `chart: { animations: { dynamicAnimation: { speed: 800 } } }` for the old pace. The first draw keeps `chart.animations.speed`.
247
+
197
248
  ### Unit shapes (`apexcharts/unit-shapes`, v6.10)
198
249
 
199
250
  A companion kit of **39 shapes** a count can take (a heart, a house, a globe, the figure 1,024 drawn in 1,024 dots). Each shape is a plain callable layout, so it plugs straight into `plotOptions.unit.positions` with `layout: 'custom'`; no registration step. The entry point is tree-shaken per shape (about 4 KB gzipped each). Dots are packed to fill the outline, so one shape serves 40 dots in a sparkline and 3,000 in a poster.
@@ -509,3 +560,5 @@ Pie, donut, polarArea, radialBar and gauge charts take `highlightFilter`, which
509
560
  14. **Setting a size on a pictogram** *(v7.0)*: there is no `pictogram.size`. A glyph is fitted to the box the dot would have occupied, so use `plotOptions.unit.size` and `spacing`. Use `pictogram.scale` only to nudge a glyph that reads light.
510
561
  15. **Pie / radial charts pinned to the top of a tall container** *(fixed v7.1)*: the centre came from `min(width, height)`, so a tall, narrow container put the circle at the top with the leftover space below it. The circle now centres in the height it actually has. If you carried a manual `offsetY` to work around this, remove it.
511
562
  16. **Sunburst, unit or waffle on the default bundle** *(v8.0)*: draws nothing and the console says the type is not registered. Add `import 'apexcharts/sunburst'` or `import 'apexcharts/unit'` next to `import ApexCharts from 'apexcharts'`. `apexcharts/unit-shapes` and `apexcharts/pictograms` do not register the unit type.
563
+ 17. **`plotOptions.radialBar.targets` on the default bundle** *(v8.5)*: the dial draws without them and the console warns once, naming the import. Add `import 'apexcharts/features/radial-targets'` (script tag `dist/features/radial-targets.js`), or use the full bundle.
564
+ 18. **Reading the dial geometry out of the SVG**: since v8.5 `chart.getRadialScales()` returns the centre, ring radii, angles and a value-to-angle mapping for a radialBar or gauge. Read it again after each render; the object is replaced.
@@ -8,9 +8,9 @@ Whether you need an import depends on the feature's or chart type's **tier**. Th
8
8
 
9
9
  - **Tier 1** is in the default `import ApexCharts from 'apexcharts'` bundle: `exports`, `legend`, `toolbar`, `annotations`, `keyboard`, `morph`, `weave`, `marks`, `facet`, `stats`. Import these only if you started from `apexcharts/core` or a per-type entry.
10
10
  - **Tier 2 is not in the default bundle.** Each item needs its own import next to it (or its script tag), or the full bundle:
11
- - features, `import 'apexcharts/features/<name>'` (script tag `dist/features/<name>.js`): `trellis`, `storyboard`, `perspectives`, `ink`, `renderer-canvas`, `link`, `measure`, `history`, `context-menu`, `highlight-filter` *(7.9)*, and since 8.0 `drilldown`, `waterfall`, `dumbbell` and `streamgraph` (those three are chart types whose renderers, rangeBar and rangeArea, are in the default bundle, so next to it you add only the feature);
11
+ - features, `import 'apexcharts/features/<name>'` (script tag `dist/features/<name>.js`): `trellis`, `storyboard`, `perspectives`, `ink`, `renderer-canvas`, `link`, `measure`, `history`, `context-menu`, `highlight-filter` *(7.9)*, since 8.0 `drilldown`, `waterfall`, `dumbbell` and `streamgraph` (those three are chart types whose renderers, rangeBar and rangeArea, are in the default bundle, so next to it you add only the feature), and `radial-targets` *(8.5)*;
12
12
  - chart types: `unit` / `waffle` (`apexcharts/unit`, `dist/unit.js`), `sunburst`, `violin`, `icicle` (`apexcharts/<type>`, `dist/<type>.js`) and `raincloud` (`apexcharts/raincloud`; script tags `dist/violin.js`, then `dist/features/raincloud.js`).
13
- - **The full bundle**, `import ApexCharts from 'apexcharts/full'` (script tag `dist/apexcharts.full.min.js`, new in 8.0), has every chart type and feature and needs no add-on import. Premium items still watermark there.
13
+ - **The full bundle**, `import ApexCharts from 'apexcharts/full'` (script tag `dist/apexcharts.full.min.js`, new in 8.0), has every chart type and feature and needs no add-on import. The one exception is the Ignite UI add-on (`apexcharts/features/ignite-ui`, 8.8), which is in no bundle. Premium items still watermark there.
14
14
 
15
15
  ```js
16
16
  import ApexCharts from 'apexcharts'
@@ -21,7 +21,7 @@ import 'apexcharts/features/trellis' // Tier 2: not in the default bundle
21
21
  <script src=".../dist/features/trellis.js"></script>
22
22
  ```
23
23
 
24
- Nothing fails silently, and since 7.9.1 the minified bundle prints these warnings too. A Tier 2 chart type that is not loaded makes `render()` reject, and the console names the import. A Tier 2 feature warns when its configuration is present but the module is not, naming the import, the script-tag file and `apexcharts.full.min.js`. Where the chart can still draw something sensible it does and says what it did: a trellis renders as a single chart, `renderer: 'canvas'` falls back to SVG, a drilldown chart draws its root level. `waterfall`, `dumbbell` and `streamgraph` without their feature draw an empty plot with one warning. `apexcharts/features/all` is the **Tier 1** set and is not a shortcut past this; the full bundle is.
24
+ Nothing fails silently, and since 7.9.1 the minified bundle prints these warnings too. A Tier 2 chart type that is not loaded makes `render()` reject, and the console names the import. A Tier 2 feature warns when its configuration is present but the module is not, naming the import, the script-tag file and `apexcharts.full.min.js`. Where the chart can still draw something sensible it does and says what it did: a trellis renders as a single chart, `renderer: 'canvas'` falls back to SVG, a drilldown chart draws its root level, a radialBar or gauge draws without its targets. `waterfall`, `dumbbell` and `streamgraph` without their feature draw an empty plot with one warning. `apexcharts/features/all` is the **Tier 1** set and is not a shortcut past this; the full bundle is.
25
25
 
26
26
  Why: 24% of the 6.10.0 default bundle was licence-gated premium code that an unlicensed user could only run watermarked, and everybody downloaded it. The default bundle went 291,654 B gzipped (6.10.0) to 252,005 B (7.0.0), and 264,326 B in 7.1.0 with the three new free chart types. At 8.0.0 it is 263,188 B, and the full bundle 381,135 B (the upstream build report's figures, gzip at the default level; they move every release). See `references/tree-shaking.md` for the full tier table and per-module sizes.
27
27
 
@@ -37,12 +37,16 @@ Carried over from v6, both respecting `prefers-reduced-motion`:
37
37
  1. **Coherent variable-length data transitions**: updates that add/remove data points animate as one coordinated motion instead of popping. Appended bars grow from the baseline, removed bars shrink and fade, line/area fills reshape over the union of old and new points, and markers/bubbles/axis labels ride along. Scatter and bubble now animate on dynamic updates for the first time. Disable per chart with `chart.animations.dynamicAnimation.enabled: false`; auto-skipped above `chart.animations.largeDatasetThreshold` (default 1000) and under `prefers-reduced-motion`.
38
38
  2. **Native-feeling mobile gestures**: two-finger pinch-zoom, two-finger pan, and kinetic inertia after a flick, with axis rails so a vertical swipe still scrolls the page. Configure via `chart.zoom.pinch` (default `'auto'`) and `chart.pan.inertia` (default `true`, `friction` default `0.92`). **`'auto'` is not the same as `true`**: it enables pinch only where the toolbar reset button is present, so a zoom is always undoable. A chart with `toolbar: { show: false }` gets no pinch zoom until `pinch: true` forces it. `chart.zoom.allowMouseWheelZoom` is gated the same way, and `chart.zoom.resetControl` (v7.4) is the other half of that bargain.
39
39
 
40
+ **The mouse wheel is cooperative (v8.3).** Where the `'auto'` wheel is offered, a bare wheel scrolls the page past the chart and briefly shows a hint (the locale's `toolbar.wheelZoomHint`, default `'Use {key} + scroll to zoom'`, where `{key}` becomes Ctrl or ⌘); Ctrl/Cmd + wheel, or a trackpad pinch, zooms. `chart.zoom.wheelHint: false` hides the hint, and `allowMouseWheelZoom: true` restores the old wheel, which zooms on every scroll, toolbar or not. A page of zoomable charts therefore scrolls normally by default.
41
+
40
42
  Also new by default: **`render()` is idempotent**: a repeated `render()` (e.g. a framework double-invoking an effect) returns the same promise instead of building a duplicate chart. `destroy()` clears it so an instance can render fresh.
41
43
 
42
- Two update behaviors worth knowing (both 6.9/6.10):
44
+ Update behaviors worth knowing:
43
45
 
44
46
  - **Function-valued options are compared by identity (6.10)**: `update()` skips a redundant render by comparing the incoming options with the previous ones. Passing a *different* function (a new `dataLabels.formatter`, custom tooltip, `plotOptions.unit.positions`) gets the render it asked for; passing the *same* function twice still skips. Building a fresh closure on every update means a render every time.
45
47
  - **A type change re-chooses type defaults (6.9)**: `updateOptions({ chart: { type } })` now re-picks the defaults that decide what a chart reads, says, hit-tests, or offers as interaction (e.g. a boxPlot-to-violin switch gets the right tooltip formatter). Deliberate paint choices and anything you set yourself are never re-chosen.
48
+ - **Your options are copied, never written into (8.1)**: the constructor, `updateOptions` and `updateSeries` leave the objects you pass exactly as you wrote them, so one options object can safely seed two charts. The merged, live config is `chart.w.config` (not in the shipped types).
49
+ - **A destroyed chart is inert, not broken (8.1)**: `updateOptions`, `updateSeries` and `appendSeries` on it log a warning and resolve with the chart instead of throwing (`appendData` resolves without a warning), and `render()` draws it afresh.
46
50
 
47
51
  ---
48
52
 
@@ -64,9 +68,9 @@ Introduced in **6.5.0**, tightened in **6.7.0**. Not every feature is free. Nine
64
68
  - the `unit` / `waffle` chart type (premium since **6.6.0**, the first premium chart type)
65
69
  - the `raincloud` chart type (premium since **7.1.0**)
66
70
 
67
- **Everything else is free and never gated**: every other chart type (the Tier 2 `sunburst`, `violin`, `icicle`, `waterfall`, `dumbbell` and `streamgraph` included), and every other module (Weave, Strata / canvas, Marks, Facet / themes, Cadence, drilldown, streaming, exports, legend, toolbar, annotations, keyboard, stats). Free here means never watermarked, not licence-free: the Community licence covers only organisations under $2M in annual revenue, operating budget, funding or equivalent resources, whichever is highest, across parent, affiliates and entities under common control (see LICENSE.md).
71
+ **Everything else is free and never gated**: every other chart type (the Tier 2 `sunburst`, `violin`, `icicle`, `waterfall`, `dumbbell` and `streamgraph` included), and every other module (Weave, Strata / canvas, Marks, Facet / themes, Cadence, drilldown, radial targets, streaming, exports, legend, toolbar, annotations, keyboard, stats). Free here means never watermarked, not licence-free: the Community licence covers only organisations under $2M in annual revenue, operating budget, funding or equivalent resources, whichever is highest, across parent, affiliates and entities under common control (see LICENSE.md).
68
72
 
69
- **Premium and Tier 2 are separate questions.** Premium is about the watermark; Tier 2 is about the bundle. Since 8.0 every premium item is Tier 2, but Tier 2 is not all premium: `renderer-canvas`, `drilldown`, `waterfall`, `dumbbell`, `streamgraph`, `sunburst`, `violin` and `icicle` are Tier 2 and free. The full bundle carries all of them, and the premium ones still watermark there.
73
+ **Premium and Tier 2 are separate questions.** Premium is about the watermark; Tier 2 is about the bundle. Since 8.0 every premium item is Tier 2, but Tier 2 is not all premium: `renderer-canvas`, `drilldown`, `radial-targets`, `waterfall`, `dumbbell`, `streamgraph`, `sunburst`, `violin` and `icicle` are Tier 2 and free. The full bundle carries all of them, and the premium ones still watermark there.
70
74
 
71
75
  ### Setting a license
72
76
 
@@ -149,7 +153,7 @@ trellis: { by: 'facet', minPanelWidth: 260 },
149
153
 
150
154
  **API.** `chart.getPanels()` returns the panels in grid order; `chart.getPanel(key)` returns one panel's own ApexCharts instance (the escape hatch to every per-chart API the trellis does not re-expose); `chart.promotePanel(key)` / `chart.restorePanels()` drive the promotion from code. `ApexCharts.trellis(el, options)` is the imperative constructor: it creates the host and starts rendering it (a later `render()` settles with the same mount). It returns `null`, with a console warning, when the trellis feature is not loaded, so check the return before calling panel methods.
151
155
 
152
- **Events.** `panelMounted`, `trellisMounted`, `panelPromoted` and `panelRestored` fire through `chart.events` (7.7.0) as well as `addEventListener`, with `(chart, payload)`; they are not in the shipped types. On scatter and bubble panels `dataPointIndex` indexes the panel's own data. To turn a trellis back into one chart, pass `trellis: null` to `updateOptions` (a cast in TypeScript); leaving the key out keeps the grid.
156
+ **Events.** `panelMounted`, `trellisMounted`, `panelPromoted` and `panelRestored` fire through `chart.events` (7.7.0) as well as `addEventListener`, with `(chart, payload)`; they are not in the shipped types. On scatter and bubble panels `dataPointIndex` indexes the panel's own data. To turn a trellis back into one chart, pass `trellis: null` to `updateOptions` (typed, and reliable, since 8.5; earlier it needed a cast in TypeScript); leaving the key out keeps the grid.
153
157
 
154
158
  **Annotations** take `scope`: absent or `'trellis'` draws in every panel through each panel's own scale, a key or array of keys restricts it.
155
159
 
@@ -188,8 +192,9 @@ The `setup(api)` facade:
188
192
 
189
193
  - `api.on(hook, fn)` / `api.off(hook, fn)`: hooks: `'afterParse' | 'afterScales' | 'draw' | 'afterUpdate' | 'destroy'`.
190
194
  - `api.layer(opts?)`: a plugin-owned drawing surface (`path`, `line`, `rect`, `circle`, `text`, `clear`); call it inside draw handlers only, layers are wiped each pass.
191
- - `api.scales` (readonly): `x(v)`, `y(v, axis?)`, `domainX`, `domainY(axis?)`, `gridWidth`, `gridHeight`, `ratios`. **`null` on a non-axis chart**, so it is a fact about the chart rather than about the host and is deliberately not a capability.
192
- - `api.data` (readonly): `[{ name?, hidden, color?, points: [{ x, y }], raw }]`.
195
+ - `api.scales` (readonly): `x(v)`, `y(v, axis?)`, `domainX`, `domainY(axis?)`, `gridWidth`, `gridHeight`, `ratios`, and *(8.0.1, capability `scale-orientation`)* `transposed` plus `point(x, y, axis?)`. **`null` on a non-axis chart**, so it is a fact about the chart rather than about the host and is deliberately not a capability. On a horizontal bar `transposed` is `true`: `x(v)` runs down the grid height and `y(v)` across the width, so place a datum with `point(x, y)` rather than pairing `x()` and `y()` yourself.
196
+ - `api.radialScales` (readonly, *8.5*, capability `radial-scales`): the dial a radialBar or gauge drew (centre, ring and band radii, angles, `angle(v)`, `point(v, r?)`), the same object as `chart.getRadialScales()`; `null` on every other type, where `scales` applies. Also on every hook payload as `radialScales`.
197
+ - `api.data` (readonly): `[{ name?, hidden, color?, points: [{ x, y }], raw, observations }]`. *(8.0.1, capability `observations`)* `observations` is the raw sample behind a histogram's bins or a boxPlot / violin summary derived from `points` (`{ values, byPoint }`, `byPoint[j]` `null` where that datum was precomputed), or `null` when `points` are the caller's own values.
193
198
  - `api.theme`: `{ mode, foreColor, seriesColor(i), token(name) }`.
194
199
  - `api.store`: per-instance mutable state bag.
195
200
  - `api.emit(name, detail?)`: dispatches `plugin:<name>:<event>` on the chart; `api.chart`, `api.el`, `api.name`, `api.version`, `api.options` round out the facade.
@@ -292,13 +297,26 @@ api.on('draw', () => {
292
297
  - **Declare from the draw handler.** Declarations are cleared with the layers at the start of every draw, so an inventory cannot outlive the drawing it describes. Declaring the same id twice replaces it rather than growing a duplicate row.
293
298
  - **Annotations carry no caller id.** The `id` on a point annotation is the key of a deferred-execution entry rather than a handle on the drawing, so entries fall back to `annotation:<type>:<index>` and take their label from `label.text` where the caller wrote one.
294
299
 
300
+ ### v7: draw a part of each value (`highlight`, 8.1)
301
+
302
+ A plugin with a second number per datum used to have only `markDerived()`, which adds a series, and a series costs the caller a legend entry, a tooltip row, an export column and a rescaled axis. `api.highlight()` draws the part solid inside the slot the value already occupies, with the whole faded behind it, as the highlight filter does:
303
+
304
+ ```js
305
+ const h = api.highlight([{ series: 'Revenue', values: [12, null, 30] }]) // parallel to that series' data
306
+ if (h) { h.update([{ series: 'Revenue', values: [8, 4, 20] }]); h.release() }
307
+ ```
308
+
309
+ **It returns `null`** when the highlight-filter feature is not loaded on the page, the chart is not an axis chart, the type draws no parts (a nested treemap included), or the caller is already showing parts of their own. Check the return on every call, since three of those can change on the caller's next update. Registering, updating and releasing each re-render the chart, coalesced to one render per turn.
310
+
311
+ **Dash values are patterns now (8.5).** `api.info.stroke.dashArray` may be a pattern string (`'8 3 2 3'`) or a per-series array whose entries are themselves patterns, and `layer.path` / `layer.line` take `dash` in the same forms, so a plugin that assumed a number must handle both.
312
+
295
313
  ### The types a plugin author works with
296
314
 
297
- Declared in the shipped `apexcharts.d.ts`: `ApexPluginAPI` (the `setup(api)` facade), `ApexPluginSeries`, `ApexPluginScales`, `ApexPluginLayer`, `ApexPluginHook`, `ApexPluginPayload`, and for the v6 additions `ApexPluginChartInfo` (`api.info`), `ApexPluginPointerEvent` (the `pointer` payload), `ApexPluginClaim` (`{ release(), update(entries) }`) and `ApexDrawnItem` (a `drawn()` row).
315
+ Declared in the shipped `apexcharts.d.ts`: `ApexPluginAPI` (the `setup(api)` facade), `ApexPluginSeries`, `ApexPluginScales`, `ApexPluginLayer`, `ApexPluginHook`, `ApexPluginPayload`, for the v6 additions `ApexPluginChartInfo` (`api.info`), `ApexPluginPointerEvent` (the `pointer` payload), `ApexPluginClaim` (`{ release(), update(entries) }`) and `ApexDrawnItem` (a `drawn()` row), and, added in 8.x, `ApexPluginHighlight` and `ApexPluginHighlightEntry` (`highlight()`), `ApexRadialScales` (`radialScales`) and `ApexDashPattern` (dash values).
298
316
 
299
- ### Typing gap (still present at 8.0.0)
317
+ ### Typing gap (still present at 8.8.1)
300
318
 
301
- `api.categories` and `data[].raw` are real at runtime (both shipped in v2) but are **not declared** in the shipped `apexcharts.d.ts`: `ApexPluginAPI` has no `categories` member and `ApexPluginSeries` is typed as `{ name?, hidden, color?, points }`. TypeScript rejects both. Cast the facade where you need them, and do not read the absence as "removed".
319
+ `api.categories` and `data[].raw` are real at runtime (both shipped in v2) but are **not declared** in the shipped `apexcharts.d.ts`: `ApexPluginAPI` has no `categories` member and `ApexPluginSeries` is typed as `{ name?, hidden, color?, points, observations }`, without `raw`. TypeScript rejects both. Cast the facade where you need them, and do not read the absence as "removed".
302
320
 
303
321
  ---
304
322
 
@@ -446,6 +464,45 @@ const options = {
446
464
 
447
465
  `await chart.refreshTokens()` re-reads the cascade after a runtime token change that does not itself trigger a render.
448
466
 
467
+ **Built-in palettes and the mode (8.7).** `theme.palette` (`'palette1'` to `'palette10'`) that you name, in the options, `window.Apex` or an `updateOptions` payload, is kept in either mode. Left unset, the palette follows the mode: `'palette4'` in dark mode, `'palette1'` otherwise. Before 8.7 a named `'palette1'` in dark mode (or `'palette4'` in light) was swapped for the mode's default.
468
+
469
+ **Font and corner tokens (from 8.8.0).** `--apx-font-family` sets the chart font and `--apx-radius-factor` scales the fixed corner radii (unset or `1` keeps today's radii). Both are core tokens like the others: no add-on needed. A token font that is still loading is read again once it has loaded, and the labels re-lay out.
470
+
471
+ ### Ignite UI add-on (from 8.8.0)
472
+
473
+ `import 'apexcharts/features/ignite-ui'`: an opt-in add-on that needs **no extra licence key** and is not a premium feature. It is in **no** bundle, `apexcharts/full` included, because it changes how a page's charts look; only a page that asks for it gets it.
474
+
475
+ With it loaded and an Ignite UI theme on the page, charts follow the theme's `--ig-*` tokens: series colours from its colour families, text, gridlines and overlay colours, tooltips and menus, the font, and (when `theme.mode` is unset) light or dark from `--ig-theme-variant`. Without it the `--ig-*` tokens are ignored, with no error, and `theme.designSystem` does nothing; the `--apx-*` tokens work either way.
476
+
477
+ ```js
478
+ // bundler: once per app, before the first render
479
+ import ApexCharts from 'apexcharts'
480
+ import 'apexcharts/features/ignite-ui'
481
+
482
+ new ApexCharts(el, {
483
+ // leave theme.mode unset so a dark Ignite UI theme can turn the chart dark
484
+ theme: {
485
+ designSystem: true, // default; false turns the Ignite UI layer off for this chart
486
+ tokens: true, // default; false turns off the --apx-* tokens AND the Ignite UI layer
487
+ },
488
+ series,
489
+ }).render()
490
+ ```
491
+
492
+ ```html
493
+ <!-- script tags: the add-on after the core -->
494
+ <script src=".../dist/apexcharts.js"></script>
495
+ <script src=".../dist/features/ignite-ui.js"></script>
496
+ ```
497
+
498
+ **Ranking**, highest first: explicit options > the chart's own CSS variables > `--apx-*` tokens > a named theme (`theme.name`) or an explicit `theme.palette` > the Ignite UI `--ig-*` tokens > built-in defaults. `colorBlindMode` and `monochrome` keep their own colours.
499
+
500
+ - **Load order.** Import it before the first render. A chart rendered earlier picks it up on its next update, resize or `chart.refreshTokens()`.
501
+ - **Stylesheet swap.** A light/dark switch that replaces the Ignite UI stylesheet does not trigger a render: call `await chart.refreshTokens()` once the new sheet has loaded (`link.onload`).
502
+ - **Fonts.** The chart takes `--ig-font-family` (below `--apx-font-family`); a web font that is still loading is read again once it has loaded, so make sure the page actually loads the font face.
503
+ - **`chart.injectStyleSheet: false`.** In the light DOM, link `dist/apexcharts-ignite-ui.css` after `dist/apexcharts.css`.
504
+ - **Other products.** The add-on registers the Ignite UI adapter shared by the Apex family, so ApexTree (2.3.0 or later), ApexSankey (1.14.0) and ApexGantt (3.21.0) on the page follow the theme too (from a script tag, only once `apexcharts.js` has loaded). Each of them also ships its own add-on (`apextree/ignite-ui`, `apexsankey/ignite-ui`, `apexgantt/ignite-ui`) for a page without this one. ApexMaps takes its own add-on, `apexmaps/ignite-ui` (1.3.0). Apex Grid's add-on, `apex-grid/ignite-ui`, exists only in the 4.0 beta on the npm `next` tag (`npm install apex-grid@next`, 4.0.0-beta.2 at the time of writing): a plain `npm install apex-grid` gets 3.6.0, which has no Ignite UI support.
505
+
449
506
  ---
450
507
 
451
508
  ## Cadence: pluggable easing
@@ -558,6 +615,16 @@ Per type:
558
615
 
559
616
  ---
560
617
 
618
+ ## Radial targets (8.5)
619
+
620
+ `import 'apexcharts/features/radial-targets'`: **Tier 2** (not in the default bundle; script tag `dist/features/radial-targets.js` after the ApexCharts script, or the full bundle). Free, never watermarked. It shipped as an add-on in 8.5 and was never in the default bundle.
621
+
622
+ Draws `plotOptions.radialBar.targets`: marks at a value on a ring (a target, a limit, last period's reading) on a radialBar, every ring of it, or a gauge of either shape. They sweep in with their ring, move from the old value on an update, hide with a legend-hidden ring and never take the pointer. Options and an example are in "Targets" in `references/circular-charts.md`.
623
+
624
+ **Without the import** the dial draws exactly as before, without the targets, and the console warns once per chart (not once per update), naming the import, the script-tag file and `apexcharts.full.min.js`. Nothing throws. Targets on any type other than radialBar or gauge are never read. The dial geometry the targets sit on, `chart.getRadialScales()`, is core and works without the add-on.
625
+
626
+ ---
627
+
561
628
  ## Ink: direct-manipulation annotation authoring
562
629
 
563
630
  `import 'apexcharts/features/ink'`: **Tier 2** (not in the default bundle) and **premium**.
@@ -747,7 +814,9 @@ chart.drillUp()
747
814
  chart.drillToRoot()
748
815
  ```
749
816
 
750
- **Async failure semantics (v6.9):** a failed fetch never strands the view. On a throw, a rejection, or a resolver returning something without a `data` array, the chart stays where it was, the breadcrumb is untouched, nothing is cached, and `drillDownError` fires. A second click while one resolve is in flight is ignored rather than starting a second request.
817
+ **Async failure semantics (v6.9):** a failed fetch never strands the view. On a throw, a rejection, or a resolver returning neither a `data` nor a `series` array, the chart stays where it was, the breadcrumb is untouched, nothing is cached, and `drillDownError` fires. A second click while one resolve is in flight is ignored rather than starting a second request.
818
+
819
+ *(8.4)* `onDrillDown` may resolve with `series` (several series, for a grouped or stacked level) instead of `data`, and may omit `id` (it defaults to the requested one). A level that settles after the viewer has navigated elsewhere is cached but not drilled into, and the overrides a level carries (`colors`, `plotOptions`, `xaxis` and the rest) are undone on the way back up.
751
820
 
752
821
  *(8.0)* A child level naming a Tier 2 chart type whose renderer the page has not loaded (`unit` / `waffle`, `sunburst`, `icicle`, `violin`, and `raincloud`, which draws through violin) is refused too: the update stops before anything moves, the level comes back off the stack, `drillDownError` fires with the error, and the `chart.drillDown(id)` promise rejects. A `waterfall`, `dumbbell` or `streamgraph` level without its feature is not refused: it navigates, then draws blank with one console warning. Load each level's chart type and feature as well as the drilldown feature.
753
822
 
@@ -797,7 +866,7 @@ const options = {
797
866
 
798
867
  ## Common Pitfalls
799
868
 
800
- 1. **Assuming the default bundle carries everything *(the #1 upgrade mistake, v6 to v7 and again 7 to 8)*.** In v6, `import ApexCharts from 'apexcharts'` was enough for every feature. At 8.0 each of these needs its own import on top of it: the features `trellis`, `storyboard`, `perspectives`, `ink`, `renderer-canvas`, `link`, `measure`, `history`, `context-menu`, `highlight-filter`, `drilldown`, `waterfall`, `dumbbell` and `streamgraph`, and the `unit` / `waffle`, `sunburst`, `violin`, `icicle` and `raincloud` chart types. Read the console: each names the import, the script-tag file and `apexcharts.full.min.js`.
869
+ 1. **Assuming the default bundle carries everything *(the #1 upgrade mistake, v6 to v7 and again 7 to 8)*.** In v6, `import ApexCharts from 'apexcharts'` was enough for every feature. At 8.0 each of these needs its own import on top of it: the features `trellis`, `storyboard`, `perspectives`, `ink`, `renderer-canvas`, `link`, `measure`, `history`, `context-menu`, `highlight-filter`, `drilldown`, `waterfall`, `dumbbell`, `streamgraph` and `radial-targets` (8.5), and the `unit` / `waffle`, `sunburst`, `violin`, `icicle` and `raincloud` chart types. Read the console: each names the import, the script-tag file and `apexcharts.full.min.js`.
801
870
  2. **Forgetting the feature import on a tree-shaken build**: a Tier 1 feature is in the default bundle but not in `apexcharts/core` or a per-type entry, so those builds still need `import 'apexcharts/features/<name>'`.
802
871
  3. **Reaching for `apexcharts/features/all` to fix either of the above**: it is the Tier 1 set only, by design (`tests/unit/feature-tier-budget.spec.js` upstream fails the build if a Tier 2 feature reappears in it). The entry that does have everything is `apexcharts/full`.
803
872
  4. **Using `api.zeroY` in a custom mark**: it does not exist. Use `ctx.scales.y(0)` for the baseline.
@@ -22,8 +22,9 @@ The wrappers' standard components load the default ApexCharts bundle, which sinc
22
22
  |---|---|
23
23
  | `unit`/`waffle`, `sunburst`, `violin`, `icicle` | `import 'apexcharts/unit'` (or `/sunburst`, `/violin`, `/icicle`) |
24
24
  | `raincloud` | `import 'apexcharts/raincloud'` |
25
- | `waterfall`, `dumbbell`, `streamgraph`, drilldown or another Tier 2 feature | `import 'apexcharts/features/<name>'` (`highlightFilter` is `features/highlight-filter`) |
25
+ | `waterfall`, `dumbbell`, `streamgraph`, drilldown or another Tier 2 feature | `import 'apexcharts/features/<name>'` (`highlightFilter` is `features/highlight-filter`, `plotOptions.radialBar.targets` is `features/radial-targets`) |
26
26
  | Everything | `import 'apexcharts/full'`, which reuses the default bundle the wrapper already loads |
27
+ | An Ignite UI theme on the page *(from 8.8.0)* | `import 'apexcharts/features/ignite-ui'` (no extra licence key; in no bundle, `full` included). Leave `theme.mode` unset so the theme's dark variant can apply; after swapping the Ignite UI stylesheet call `ApexCharts.exec('<chart.id>', 'refreshTokens')` (from 8.8.0; returns the update Promise, same as `ApexCharts.getChartByID('<chart.id>').refreshTokens()`) |
27
28
 
28
29
  ```jsx
29
30
  import Chart from 'react-apexcharts'
@@ -242,7 +243,7 @@ updateChart() {
242
243
  <div id="chart"></div>
243
244
 
244
245
  <!-- CDN, pinned to a release -->
245
- <script src="https://cdnjs.cloudflare.com/ajax/libs/apexcharts/8.2.0/apexcharts.min.js"></script>
246
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts@8.8.1/dist/apexcharts.min.js"></script>
246
247
 
247
248
  <script>
248
249
  const options = {
@@ -260,18 +261,16 @@ updateChart() {
260
261
 
261
262
  ```html
262
263
  <!-- default bundle -->
263
- <script src="https://cdnjs.cloudflare.com/ajax/libs/apexcharts/8.2.0/apexcharts.min.js"></script>
264
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts@8.8.1/dist/apexcharts.min.js"></script>
264
265
  <!-- one add-on next to it: an opt-in chart type -->
265
- <script src="https://cdnjs.cloudflare.com/ajax/libs/apexcharts/8.2.0/sunburst.js"></script>
266
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts@8.8.1/dist/sunburst.js"></script>
266
267
 
267
- <!-- or the full bundle: every chart type and feature, no add-ons -->
268
- <script src="https://cdnjs.cloudflare.com/ajax/libs/apexcharts/8.2.0/apexcharts.full.min.js"></script>
269
-
270
- <!-- the same files on jsDelivr keep the dist/ folder in the path -->
271
- <script src="https://cdn.jsdelivr.net/npm/apexcharts@8.2.0/dist/apexcharts.min.js"></script>
272
- <script src="https://cdn.jsdelivr.net/npm/apexcharts@8.2.0/dist/sunburst.js"></script>
268
+ <!-- or the full bundle: every chart type and feature, no add-ons (except ignite-ui, which is in no bundle) -->
269
+ <script src="https://cdn.jsdelivr.net/npm/apexcharts@8.8.1/dist/apexcharts.full.min.js"></script>
273
270
  ```
274
271
 
272
+ jsDelivr serves each release from npm as soon as it is published, and keeps the `dist/` folder in the path. cdnjs mirrors the same files without `dist/` (`https://cdnjs.cloudflare.com/ajax/libs/apexcharts/<version>/apexcharts.min.js`) but can lag a release by days: use it only when the environment allows nothing else, with the newest version it lists.
273
+
275
274
  **Always write an exact version**, as above, never a major channel (`apexcharts@<major>`) or the unversioned URL: sandboxes that host generated pages (artifacts, previews) commonly reject a URL without an exact version, and an exact pin keeps a page working when the next major changes what the default bundle holds. **Never write a 3.x or 4.x URL** (`.../apexcharts/3.54.1/...`): those are releases from 2024 and early 2025, and this skill does not describe them. If an environment only accepts an older release, use the newest one it accepts with the same major version as the URLs above, since this skill applies to that whole major. To stay on an older major, pin a release from it. The other add-ons are `unit.js`, `violin.js`, `icicle.js` and `features/<name>.js` beside `apexcharts.min.js`, and may load before or after the main script.
276
275
 
277
276
  ---
@@ -283,3 +282,4 @@ updateChart() {
283
282
  3. **Not destroying on unmount (vanilla API in React/Vue)** — causes memory leaks and duplicate charts. The official wrappers handle this automatically.
284
283
  4. **Mutating config objects in place (Vue)** — deep mutations may not trigger reactivity. Replace the entire object or use `ref` at the right level.
285
284
  5. **Rendering in hidden containers** — charts rendered in hidden tabs/modals have zero dimensions. Call `chart.updateOptions({})` or trigger a resize after showing the container.
285
+ 6. **Sizing the host element *(v8.6)***: ApexCharts no longer writes a `min-height` on the element you render into; the height it reserves is a `min-height` on its own `.apexcharts-canvas` wrapper. A `min-height` you give the host (style prop or class) now applies while the chart is mounted and survives `destroy()`, so a destroy and re-create on the same element (React StrictMode's double mount, Vue and Angular refreshes) no longer leaves the next chart in a host with no minimum height. Code that read the reservation from the host should read it from `.apexcharts-canvas`.
@@ -179,7 +179,9 @@ plotOptions: {
179
179
  parents: { // how branch containers are drawn once the data is nested
180
180
  show: 'auto' // 'auto' (on when the data carries children) | true | false
181
181
  // plus header/label styling and a tooltip.formatter receiving
182
- // { name, value, depth, leafCount, percentOfParent, percentOfTotal, node, w }
182
+ // { name, value, depth, leafCount, percentOfParent, percentOfTotal, node, w,
183
+ // series, seriesIndex, dataPointIndex: -1, ctx } (the last four since v8.4)
184
+ // and returning markup, an Element, or null / undefined / false to keep the built-in rows
183
185
  },
184
186
  levels: [ /* per-depth overrides of `parents`, indexed from the outermost drawn group */ ]
185
187
  }
@@ -188,6 +190,8 @@ plotOptions: {
188
190
 
189
191
  The hierarchy resolver is shared with sunburst, including the `drilldown: '<id>'` adapter (opted into via `nested.drilldownAsLevels`).
190
192
 
193
+ **Branch tooltips (v8.2, v8.4).** A hovered branch gets its own tooltip (`.apexcharts-treemap-tooltip`, v8.2) with the branch name, total and shares. Since v8.4 `tooltip.custom` runs on branches too, called as the sunburst and icicle call it: `dataPointIndex: -1`, `seriesIndex` the branch's series, `node`, `value` (the branch total), `percentOfParent` and `percentOfTotal` (0 to 100, one decimal). `plotOptions.treemap.parents.tooltip.formatter`, when set, owns branch tooltips instead and `tooltip.custom` keeps the leaves. A `null` / `undefined` return keeps the built-in rows. **A `tooltip.custom` written for leaves must return `null` when `node` is set**, or it reads `series[seriesIndex][-1]` on every branch hover.
194
+
191
195
  ### Icicle (v7.6)
192
196
 
193
197
  Same hierarchy as the sunburst, drawn in cartesian coordinates: one band per depth level, each child sized inside its parent's extent along the value axis. Axis-style `[{ data: [...] }]` wrapper, `{ x, y, children }` nodes to any depth.
@@ -213,6 +217,7 @@ const options = {
213
217
  - A branch may **omit its own `y`** and be the sum of its children. This is the documented shape for both partition types, and it only started working in v7.6: before that the non-axis parser dropped any node carrying `children` without `x` and `y`, and the chart drew nothing at all while warning about pie data.
214
218
  - A node may carry `drilldown: '<id>'` instead of `children`, and the matching `drilldown.series` entry is read as the next level. It is read as plain data, so no drilldown feature import is needed.
215
219
  - Sibling order follows the array by default (`sort: 'none'`). Set `plotOptions.icicle.sort` to `'value'` or `'name'` to override it.
220
+ - `tooltip.custom` *(v8.4)* runs once per hovered node with `{ seriesIndex: 0, dataPointIndex: -1, node, percentOfParent, percentOfTotal, series, w, ctx }`, the same call the sunburst makes; return markup or an Element, or `null` to keep the built-in row. Node names are escaped in the built-in tooltip *(v8.3.1)*, so markup in a name shows as text.
216
221
 
217
222
  **Choosing between icicle and sunburst.** Both resolve the same tree. An icicle keeps labels horizontal at every depth and puts depth on a straight axis, so same-depth siblings line up across branches and deep trees stay readable; a sunburst spends its area radially and reads better for shallow, wide trees. `direction: 'up'` is the flame-graph orientation, for call stacks and path funnels.
218
223
 
@@ -382,3 +387,4 @@ A click that would not change the view is refused rather than performed: clickin
382
387
  6. **`chart.type: 'icicle'` on the default bundle (v7.6)**: icicle is Tier 2 and the default build carries no class for it, so the chart fails to render and the console names the import. Add `import 'apexcharts/icicle'` next to `import ApexCharts from 'apexcharts'` (or load `dist/icicle.js`). The default `apexcharts.js` does not carry the class; the full bundle (`apexcharts/full`, `dist/apexcharts.full.min.js`, v8.0) does.
383
388
  7. **Reaching for `zoomType: 'both'` to make a branch fill the plot** — `'value'` already stretches the branch across the full width; what `'both'` additionally does is move every level, which costs the reader their place in the tree. Change it only when the ancestors genuinely do not matter.
384
389
  8. **Expecting `sort: 'value'` on a flame graph** — `'name'` is the flame-graph convention, because it holds a frame in the same place across profiles so two runs of one program can be compared by eye.
390
+ 9. **A data-point `tooltip.custom` on a nested treemap, sunburst or icicle** *(v8.4)*: it now runs on branches and partition nodes too, with `dataPointIndex: -1` and the hovered `node`. Return `null` when `opts.node` is set to keep the built-in tooltip there, or give treemap branches `plotOptions.treemap.parents.tooltip.formatter`.
package/references/ssr.md CHANGED
@@ -50,6 +50,8 @@ const svgString = await ApexCharts.renderToString(
50
50
  // svgString is raw <svg>...</svg> markup
51
51
  ```
52
52
 
53
+ The legend is HTML beside the SVG, so this standalone SVG carries **no legend** and its plot fills the chart. Use `renderToHTML` for a chart with its legend.
54
+
53
55
  ### renderToHTML(options, ssrOptions?)
54
56
 
55
57
  Returns an HTML string with a wrapper `<div>` containing the SVG, ready for hydration:
@@ -76,6 +78,8 @@ const htmlString = await ApexCharts.renderToHTML(
76
78
  // travels in data-apexcharts-config, which is what hydration reads.
77
79
  ```
78
80
 
81
+ *(v8.2)* The HTML includes the legend and its stylesheet beside the SVG, as the browser draws it; before 8.2 it had none. Set `legend: { show: false }` for the old output. Series names and categories in it are escaped *(v8.0.1, v8.4)*, so data you do not control cannot inject markup.
82
+
79
83
  ---
80
84
 
81
85
  ## Client-Side Hydration
@@ -92,6 +96,8 @@ import ApexCharts from 'apexcharts/ssr' // not 'apexcharts' or 'apexcharts/cli
92
96
  const chart = ApexCharts.hydrate(document.querySelector('[data-apexcharts-hydrate]'))
93
97
  ```
94
98
 
99
+ The options you passed to `renderToHTML` travel with it and **stand as written** on the client *(v8.1)*: a `chart.animations.enabled: false` or `chart.toolbar.show: false` you set for the server stays off after hydration (before 8.1 hydration switched both back on). To change them on the client, pass them in `clientOptions`, e.g. `hydrate(el, { chart: { toolbar: { show: true } } })`.
100
+
95
101
  ### hydrateAll(selector?, clientOptions?)
96
102
 
97
103
  ```js
@@ -26,7 +26,7 @@ import ApexCharts from 'apexcharts/full' // script tag: dist/apexcharts.full.m
26
26
  | 8.0.0 default bundle | 263,188 B (**-9.8%**) |
27
27
  | 8.0.0 full bundle | 381,135 B |
28
28
 
29
- Unversioned CDN URLs serve 8.0. Pin `apexcharts@7` to stay on 7.
29
+ Unversioned CDN URLs serve the latest 8.x release. Pin a 7.x release to stay on 7.
30
30
 
31
31
  ## ⚠️ What changed in v7.0
32
32
 
@@ -52,7 +52,7 @@ ApexCharts supports five import strategies with different bundle sizes:
52
52
  | Strategy | Import | Includes |
53
53
  |---|---|---|
54
54
  | Default bundle | `import ApexCharts from 'apexcharts'` | line, area, scatter, bubble, rangeArea, bar, column, rangeBar, candlestick, boxPlot, pie, donut, polarArea, radialBar, radar, heatmap, treemap (plus the funnel, pyramid, histogram and gauge aliases), and the **Tier 1** features. **Not** the Tier 2 chart types or features *(v8.0)*. |
55
- | Full bundle *(v8.0)* | `import ApexCharts from 'apexcharts/full'` / `dist/apexcharts.full.min.js` | Every chart type and every feature, Tier 2 included, plus the unit-shapes and pictograms catalogs. Premium items stay licence-gated. |
55
+ | Full bundle *(v8.0)* | `import ApexCharts from 'apexcharts/full'` / `dist/apexcharts.full.min.js` | Every chart type and every feature, Tier 2 included, plus the unit-shapes and pictograms catalogs. Not the Ignite UI add-on *(8.8)*, which is in no bundle. Premium items stay licence-gated. |
56
56
  | Per-type entry | `import ApexCharts from 'apexcharts/line'` | Specific chart family + core, plus any feature the type needs (no legend, toolbar, exports or other optional features) |
57
57
  | Bare core | `import ApexCharts from 'apexcharts/core'` | Core class only — must manually register everything |
58
58
  | Lean core, no bundler *(v7.0)* | `<script src=".../dist/apexcharts.core.js">` | Script-tag equivalent of bare core, assembled from separate tags. See below. |
@@ -123,7 +123,7 @@ import 'apexcharts/bar' // side-effect: registers bar types onto the same clas
123
123
  Two questions decide whether you need a `features/*` import:
124
124
 
125
125
  1. **Which entry point did you start from?** `apexcharts/core` and the per-type entries carry no optional features (a per-type entry brings only the feature its own type needs), so every feature you want needs its import.
126
- 2. **Which tier is the feature?** Tier 1 is in the default `apexcharts` bundle. **Tier 2 is not**, so it needs its import there too. Only the full bundle (`apexcharts/full`, *v8.0*) has every feature.
126
+ 2. **Which tier is the feature?** Tier 1 is in the default `apexcharts` bundle. **Tier 2 is not**, so it needs its import there too. Only the full bundle (`apexcharts/full`, *v8.0*) has every Tier 2 feature; the Ignite UI add-on is in no bundle.
127
127
 
128
128
  ### Tier 1: in the default `apexcharts` bundle
129
129
 
@@ -166,12 +166,15 @@ Required whatever entry point you used, the default `apexcharts` bundle included
166
166
  | Waterfall *(v7.1; Tier 2 since v8.0)* | `import 'apexcharts/features/waterfall'` | 2.8 KB | no | The `waterfall` chart type |
167
167
  | Dumbbell *(v7.1; Tier 2 since v8.0)* | `import 'apexcharts/features/dumbbell'` | 2.1 KB | no | The `dumbbell` chart type |
168
168
  | Raincloud *(v7.1)* | `import 'apexcharts/raincloud'` | 2.4 KB + violin 6.4 KB | yes | The `raincloud` chart type. The entry brings violin and the feature; `apexcharts/features/raincloud` alone works only where violin is already registered *(v8.0)* |
169
+ | Radial targets *(v8.5)* | `import 'apexcharts/features/radial-targets'` | 2.9 KB (at 8.7.0) | no | `plotOptions.radialBar.targets`: target and limit marks on a radialBar ring or a gauge. Never in the default bundle: it shipped as an add-on |
169
170
 
170
171
  Storyboard registers Perspectives, so importing both costs no more than Storyboard alone.
171
172
 
173
+ **In no bundle at all: the Ignite UI add-on *(from 8.8.0)*.** `import 'apexcharts/features/ignite-ui'` (script tag `dist/features/ignite-ui.js`, after `apexcharts.js`) makes charts follow an Ignite UI theme on the page. Unlike the Tier 2 features it is not in `apexcharts/full` either, since it changes how the page's charts look: only a page that imports it gets it. No extra licence key, 3.6 KB gzip (at 8.8.1). Without it the page's `--ig-*` tokens are ignored silently (no warning) and `theme.designSystem` does nothing. See "Ignite UI add-on" in `feature-platform.md`.
174
+
172
175
  **`apexcharts/features/all` does not include Tier 2**, by design: upstream has a tier-budget test that fails the build if a Tier 2 feature reappears in it.
173
176
 
174
- **Nothing fails silently on Tier 2.** Each module warns in the console when its configuration is present but the module is not, and the warning names the ESM import, the script-tag file and `apexcharts.full.min.js`. Where the chart can still draw something sensible it does and says what it did instead: a trellis renders as a single chart, `renderer: 'canvas'` falls back to SVG.
177
+ **Nothing fails silently on Tier 2.** Each module warns in the console when its configuration is present but the module is not, and the warning names the ESM import, the script-tag file and `apexcharts.full.min.js`. Where the chart can still draw something sensible it does and says what it did instead: a trellis renders as a single chart, `renderer: 'canvas'` falls back to SVG, a radialBar or gauge draws its dial without `plotOptions.radialBar.targets`.
175
178
 
176
179
  ---
177
180
 
@@ -189,7 +192,7 @@ Tree-shaking only ever helped people with a build step. A page using a `<script>
189
192
 
190
193
  The opt-in chart types have their own files rather than `features/*` ones: `dist/unit.js`, `dist/sunburst.js`, `dist/violin.js` and `dist/icicle.js`, and a raincloud page loads `dist/violin.js` then `dist/features/raincloud.js`. On `apexcharts.core.js`, violin (and so raincloud) also needs `dist/bar.js`.
191
194
 
192
- Every Tier 2 feature has a `dist/features/<name>.js` artifact for this channel too, and a default-bundle page still needs it. Add-on tags may load before or after the ApexCharts script *(v8.0)*. `dist/apexcharts.full.min.js` needs none of them.
195
+ Every Tier 2 feature has a `dist/features/<name>.js` artifact for this channel too, and a default-bundle page still needs it. Add-on tags may load before or after the ApexCharts script *(v8.0)*. `dist/apexcharts.full.min.js` needs none of them. The exception is `dist/features/ignite-ui.js` *(from 8.8.0)*: it is in no bundle, `full` included, so add its tag to a full-bundle page too if that page should follow an Ignite UI theme. Like the other add-ons it may load before or after the ApexCharts script; after `apexcharts.js` is the recommended order.
193
196
 
194
197
  ```html
195
198
  <script src=".../dist/apexcharts.js"></script>
@@ -210,7 +213,7 @@ It depends on the tier.
210
213
  - `addXaxisAnnotation()` does nothing
211
214
  - `dataURI()` / `exportToCSV()` throw because the feature isn't registered
212
215
 
213
- **Tier 2 features announce themselves.** Each warns in the console when its configuration is present but the module is not, naming the ESM import, the script-tag file and `apexcharts.full.min.js`, and degrades predictably where it can: a `trellis` config renders as one ordinary chart, `renderer: 'canvas'` falls back to SVG. If a chart is quietly missing a feature you configured, **check the console before the config**. Since 7.9.1 the minified `apexcharts.min.js` prints these warnings too.
216
+ **Tier 2 features announce themselves.** Each warns in the console when its configuration is present but the module is not, naming the ESM import, the script-tag file and `apexcharts.full.min.js`, and degrades predictably where it can: a `trellis` config renders as one ordinary chart, `renderer: 'canvas'` falls back to SVG, targets on a radialBar or gauge are left off the dial (one warning per chart, not one per update). If a chart is quietly missing a feature you configured, **check the console before the config**. Since 7.9.1 the minified `apexcharts.min.js` prints these warnings too.
214
217
 
215
218
  **Opt-in chart types throw *(v8.0)*.** `unit`, `waffle`, `sunburst`, `violin`, `icicle` and `raincloud` without their entry make `render()` reject, and the console prints one error naming the import, the script tag and the full bundle. An `updateOptions()` that switches to an unloaded type keeps the current chart.
216
219
 
@@ -291,7 +294,7 @@ export default {
291
294
 
292
295
  ## Common Pitfalls
293
296
 
294
- 1. **Assuming the default bundle still has everything *(v7, v8)***: the Tier 2 chart types (`unit`/`waffle`, `sunburst`, `violin`, `icicle`, `raincloud`) and Tier 2 features (the nine since 7.0, highlight-filter since 7.9, and drilldown, waterfall, dumbbell and streamgraph since 8.0) need their own import on top of `import ApexCharts from 'apexcharts'`, or the full bundle. This is the most common upgrade failure, v6 to v7 and v7 to v8.
297
+ 1. **Assuming the default bundle still has everything *(v7, v8)***: the Tier 2 chart types (`unit`/`waffle`, `sunburst`, `violin`, `icicle`, `raincloud`) and Tier 2 features (the nine since 7.0, highlight-filter since 7.9, drilldown, waterfall, dumbbell and streamgraph since 8.0, and radial-targets since 8.5) need their own import on top of `import ApexCharts from 'apexcharts'`, or the full bundle. This is the most common upgrade failure, v6 to v7 and v7 to v8.
295
298
  2. **Reaching for `apexcharts/features/all` to fix it**: that is the Tier 1 set by design and pulls in no Tier 2 module.
296
299
  3. **Missing feature imports on a tree-shaken build**: Tier 1 features fail silently. If legend/toolbar/annotations don't appear, check imports.
297
300
  4. **Adding a per-type entry for a type the default bundle already has** (`apexcharts/line`, `apexcharts/bar`, `apexcharts/waterfall` next to `apexcharts`): that is a second copy of the renderer. Next to `apexcharts`, add only the opt-in entries (`apexcharts/unit`, `/sunburst`, `/violin`, `/icicle`, `/raincloud`) and `apexcharts/features/*`. *(v7.0 fixed the related internal bug where the default bundle inlined its own core copy while add-ons resolved `apexcharts/core`, so an app importing both got two classes, ~130 KB gzipped of duplicate core, and a feature that never registered. They now share one core.)*