ApexCharts AI Skill
Framework wrapper detection — check
package.jsonbefore generating code.
react→ usereact-apexchartsinstead of the core API.vue(Vue 3) → usevue3-apexcharts. Vue 2 →vue-apexcharts.@angular/core→ useng-apexcharts.Wrappers handle
destroy()automatically on unmount, accept reactive props, and forward events as idiomatic framework events. Use the core API directly only when no framework is detected, or when the user explicitly asks for vanilla. Seereferences/framework-wrappers.md.
1. Critical Rules
- Always call
chart.render()afternew ApexCharts(el, options). The constructor does not render. - Always call
chart.destroy()before creating a new chart on the same element. Failing to do so causes memory leaks and duplicate charts (especially in React/Vue). - Series data format is chart-type-specific. Refer to the Data Format Table below. This is the #1 source of AI mistakes.
yaxismust be an array when using multiple y-axes. Each entry needs aseriesNameto map to the correct series.tooltip.sharedandtooltip.intersectare mutually exclusive.shared: trueshows all series at an x-position.intersect: trueshows only the hovered point.- Use
null(notundefinedor empty string) for missing data points.undefinedis silently ignored and breaks the chart. chart.stacked: trueonly works withbarandareachart types.- Responsive breakpoints must be in ascending order in the
responsivearray. - For mixed/combo charts, set
typeon each individual series object, not just onchart.type. - RadialBar values must be 0–100 (they represent percentages).
- Color hex values must include the
#prefix (e.g.,'#FF5733', not'FF5733'). - Tree-shaking: importing
apexcharts/coregives you a bare class — you must also import chart-type entries and feature entries separately.
2. Series Data Format Table
This is the most critical reference. Using the wrong data format is the #1 cause of broken charts.
Axis Charts (line, area, bar, scatter, etc.)
| Chart Type | chart.type |
Series Format | Minimal Example |
|---|---|---|---|
| Line | 'line' |
[{ name, data: [number | null] }] or [{ name, data: [{ x, y }] }] |
series: [{ name: 'Sales', data: [30, 40, null, 50] }] |
| Area | 'area' |
Same as line | series: [{ name: 'Views', data: [10, 20, 30] }] |
| Bar / Column | 'bar' |
Same as line. Defaults to vertical columns; set plotOptions.bar.horizontal: true for horizontal bars. |
series: [{ name: 'Revenue', data: [44, 55, 41] }] |
| Scatter | 'scatter' |
[{ name, data: [{ x, y }] }] — always use XY format |
series: [{ name: 'Points', data: [{ x: 1, y: 5 }, { x: 2, y: 10 }] }] |
| Bubble | 'bubble' |
[{ name, data: [{ x, y, z }] }] — z is required (bubble size) |
series: [{ name: 'Data', data: [{ x: 1, y: 30, z: 10 }] }] |
| Range Area | 'rangeArea' |
[{ name, data: [{ x, y: [low, high] }] }] |
series: [{ name: 'Temp', data: [{ x: 'Jan', y: [5, 15] }] }] |
| Range Bar | 'rangeBar' |
[{ name, data: [{ x, y: [start, end] }] }] — for timeline/Gantt, use timestamps |
series: [{ name: 'Tasks', data: [{ x: 'Design', y: [1, 5] }] }] |
| Candlestick | 'candlestick' |
[{ data: [{ x, y: [O, H, L, C] }] }] — array of 4: Open, High, Low, Close |
series: [{ data: [{ x: new Date('2024-01-01'), y: [51, 56, 48, 53] }] }] |
| Box Plot | 'boxPlot' |
[{ data: [{ x, y: [min, Q1, median, Q3, max] }] }] — array of 5 |
series: [{ data: [{ x: 'Group A', y: [10, 20, 30, 40, 50] }] }] |
| Heatmap | 'heatmap' |
[{ name, data: [{ x, y: number }] }] — y is the intensity value |
series: [{ name: 'Mon', data: [{ x: '10am', y: 45 }] }] |
| Treemap | 'treemap' |
[{ data: [{ x, y: number }] }] — y is the area/value |
series: [{ data: [{ x: 'Item A', y: 100 }, { x: 'Item B', y: 60 }] }] |
| Radar | 'radar' |
[{ name, data: [number] }] + xaxis: { categories: [...] } |
series: [{ name: 'Skill', data: [80, 50, 30, 40, 100] }] |
Non-Axis Charts (pie, donut, radialBar, polarArea)
These use a flat number array for series, NOT the object format:
// CORRECT — flat number array + labels
{
chart: { type: 'pie' }, // or 'donut', 'polarArea', 'radialBar'
series: [44, 55, 13, 43, 22],
labels: ['Team A', 'Team B', 'Team C', 'Team D', 'Team E']
}
3. Package / Module Map
# Full bundle (all chart types + all features)
import ApexCharts from 'apexcharts'
# Bare core (no chart types, no optional features — must register manually)
import ApexCharts from 'apexcharts/core'
# Per-type entry points (registers specific chart types + core)
import ApexCharts from 'apexcharts/line' # line, area, scatter, bubble, rangeArea
import ApexCharts from 'apexcharts/area' # same as /line
import ApexCharts from 'apexcharts/scatter' # same as /line
import ApexCharts from 'apexcharts/bubble' # same as /line
import ApexCharts from 'apexcharts/rangeArea' # same as /line
import ApexCharts from 'apexcharts/bar' # bar, column, rangeBar
import ApexCharts from 'apexcharts/column' # same as /bar
import ApexCharts from 'apexcharts/rangeBar' # same as /bar
import ApexCharts from 'apexcharts/candlestick' # candlestick, boxPlot
import ApexCharts from 'apexcharts/boxPlot' # same as /candlestick
import ApexCharts from 'apexcharts/pie' # pie, donut, polarArea
import ApexCharts from 'apexcharts/donut' # same as /pie
import ApexCharts from 'apexcharts/polarArea' # same as /pie
import ApexCharts from 'apexcharts/radialBar' # radialBar only
import ApexCharts from 'apexcharts/radar' # radar only
import ApexCharts from 'apexcharts/heatmap' # heatmap only
import ApexCharts from 'apexcharts/treemap' # treemap only
# Optional features (side-effect imports — just import, no default export needed)
import 'apexcharts/features/exports' # PNG/SVG/CSV export methods
import 'apexcharts/features/legend' # Interactive legend component
import 'apexcharts/features/toolbar' # Toolbar (zoom, pan, download buttons)
import 'apexcharts/features/annotations' # X/Y/point/text/image annotations
import 'apexcharts/features/keyboard' # Keyboard navigation (accessibility)
import 'apexcharts/features/all' # All features at once
# SSR (server-side rendering)
import ApexCharts from 'apexcharts/ssr' # Node.js: renderToString, renderToHTML
import ApexCharts from 'apexcharts/client' # Browser: explicit client import for hydration
Note: When using apexcharts (full bundle), all chart types and features are included automatically. Tree-shaking entries (/core, /line, etc.) are for reducing bundle size.
4. Core Lifecycle Pattern
import ApexCharts from 'apexcharts'
// 1. Define options
const options = {
chart: {
type: 'line',
height: 350
},
series: [{
name: 'Sales',
data: [30, 40, 35, 50, 49, 60, 70]
}],
xaxis: {
categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
}
}
// 2. Create chart instance
const chart = new ApexCharts(document.querySelector('#chart'), options)
// 3. Render (REQUIRED — constructor alone does not display the chart)
await chart.render()
// 4. Update data or options later
await chart.updateSeries([{
name: 'Sales',
data: [10, 20, 15, 30, 29, 40, 50]
}])
// Or merge new config options
await chart.updateOptions({
title: { text: 'Updated Chart' }
})
// 5. Destroy when done (REQUIRED before unmounting in SPA frameworks)
chart.destroy()
5. Formatter Function Signatures
| Config Path | Signature | Returns |
|---|---|---|
xaxis.labels.formatter |
(value: string | number, timestamp?: number, opts?) => string |
Formatted x-axis tick label |
yaxis.labels.formatter |
(value: number, opts?) => string |
Formatted y-axis tick label |
tooltip.x.formatter |
(value: number, opts?) => string |
Tooltip x-value text |
tooltip.y.formatter |
(value: number, opts?) => string |
Tooltip y-value text |
tooltip.y.title.formatter |
(seriesName: string, opts?) => string |
Tooltip series title |
tooltip.z.formatter |
(value: number) => string |
Tooltip z-value (bubble) |
dataLabels.formatter |
(value: number | string | number[], opts?) => string | number |
Data label text |
legend.formatter |
(legendName: string, opts?) => string |
Legend item text |
plotOptions.pie.donut.labels.value.formatter |
(val: string) => string |
Donut center value |
plotOptions.pie.donut.labels.total.formatter |
(w: { globals, config }) => string |
Donut center total |
plotOptions.radialBar.dataLabels.value.formatter |
(val: number) => string |
RadialBar center value |
Important: All formatters must return a string (or number for dataLabels.formatter). Never return undefined.
6. Pitfalls & Anti-Patterns
Pitfall 1: Wrong series data format for chart type
❌ WRONG — pie chart with axis-chart series format:
{ chart: { type: 'pie' }, series: [{ name: 'A', data: [44, 55] }] }
✅ CORRECT — pie chart uses flat number array + labels:
{ chart: { type: 'pie' }, series: [44, 55, 13], labels: ['A', 'B', 'C'] }
Pitfall 2: Not calling render()
❌ WRONG — chart never appears:
const chart = new ApexCharts(el, options)
// Missing render() call!
✅ CORRECT:
const chart = new ApexCharts(el, options)
await chart.render()
Pitfall 3: Not destroying before re-creating (React/Vue memory leak)
❌ WRONG — creates duplicate charts:
useEffect(() => {
const chart = new ApexCharts(ref.current, options)
chart.render()
}, [options])
✅ CORRECT — destroy on cleanup:
useEffect(() => {
const chart = new ApexCharts(ref.current, options)
chart.render()
return () => chart.destroy()
}, [options])
Pitfall 4: Mixing xaxis.type with wrong data format
❌ WRONG — datetime axis with string dates (not timestamps):
{
xaxis: { type: 'datetime' },
series: [{ data: [{ x: 'January 2024', y: 30 }] }]
}
✅ CORRECT — datetime axis with timestamps or Date objects:
{
xaxis: { type: 'datetime' },
series: [{ data: [{ x: new Date('2024-01-01').getTime(), y: 30 }] }]
}
Also: do NOT use xaxis.categories when your data already has { x, y } format — categories are ignored.
Pitfall 5: Multiple y-axes not as array
❌ WRONG — yaxis as single object:
{
series: [{ name: 'Revenue', data: [...] }, { name: 'Profit', data: [...] }],
yaxis: { title: { text: 'Revenue' } }
}
✅ CORRECT — yaxis as array with seriesName mapping:
{
series: [{ name: 'Revenue', data: [...] }, { name: 'Profit', data: [...] }],
yaxis: [
{ seriesName: 'Revenue', title: { text: 'Revenue ($)' } },
{ seriesName: 'Profit', opposite: true, title: { text: 'Profit (%)' } }
]
}
Pitfall 6: tooltip.shared vs tooltip.intersect
❌ WRONG — both enabled (conflicting):
{ tooltip: { shared: true, intersect: true } }
✅ CORRECT — pick one mode:
// Mode A: Show all series values at x-position (default for line/area)
{ tooltip: { shared: true, intersect: false } }
// Mode B: Show only hovered data point (better for scatter)
{ tooltip: { shared: false, intersect: true } }
Pitfall 7: Wrong formatter signatures
❌ WRONG — using y-axis formatter signature for tooltip:
{
tooltip: { y: { formatter: (val, timestamp, opts) => `$${val}` } }
}
✅ CORRECT — tooltip.y.formatter only receives (val, opts):
{
tooltip: { y: { formatter: (val, opts) => `$${val}` } },
yaxis: { labels: { formatter: (val) => `$${val.toFixed(0)}` } }
}
Pitfall 8: undefined instead of null for missing data
❌ WRONG — undefined breaks the chart:
{ series: [{ data: [10, undefined, 30, undefined, 50] }] }
✅ CORRECT — use null:
{ series: [{ data: [10, null, 30, null, 50] }] }
Pitfall 9: Stacking on unsupported chart types
❌ WRONG — stacking on scatter chart:
{ chart: { type: 'scatter', stacked: true } }
✅ CORRECT — stacking only works on bar and area:
{ chart: { type: 'bar', stacked: true } }
// or
{ chart: { type: 'area', stacked: true } }
Pitfall 10: Mixed/combo charts missing per-series type
❌ WRONG — no type on individual series:
{
chart: { type: 'line' },
series: [
{ name: 'Sales', data: [10, 20, 30] }, // renders as line
{ name: 'Profit', data: [5, 12, 18] } // also renders as line!
]
}
✅ CORRECT — set type per series:
{
chart: { type: 'line' },
series: [
{ name: 'Sales', type: 'column', data: [10, 20, 30] },
{ name: 'Profit', type: 'line', data: [5, 12, 18] }
]
}
Pitfall 11: RadialBar values > 100
❌ WRONG — raw values (renders incorrectly):
{ chart: { type: 'radialBar' }, series: [340, 520, 190] }
✅ CORRECT — use percentages 0–100:
{ chart: { type: 'radialBar' }, series: [76, 67, 61], labels: ['A', 'B', 'C'] }
Pitfall 12: Colors without # prefix
❌ WRONG:
{ colors: ['FF5733', '33FF57'] }
✅ CORRECT:
{ colors: ['#FF5733', '#33FF57'] }
Pitfall 13: Responsive breakpoints not ascending
❌ WRONG — descending order:
{ responsive: [{ breakpoint: 1024, options: {...} }, { breakpoint: 480, options: {...} }] }
✅ CORRECT — ascending order:
{ responsive: [{ breakpoint: 480, options: {...} }, { breakpoint: 1024, options: {...} }] }
Pitfall 14: Tree-shaking — missing feature imports
❌ WRONG — toolbar/legend/annotations silently missing:
import ApexCharts from 'apexcharts/line'
// No feature imports! Legend, toolbar, annotations won't appear.
✅ CORRECT — import needed features:
import ApexCharts from 'apexcharts/line'
import 'apexcharts/features/legend'
import 'apexcharts/features/toolbar'
import 'apexcharts/features/annotations'
Pitfall 15: SSR — wrong import path
❌ WRONG — using browser bundle in Node.js:
// On server:
import ApexCharts from 'apexcharts'
await ApexCharts.renderToString(options) // renderToString doesn't exist!
✅ CORRECT — use SSR entry point:
// On server:
import ApexCharts from 'apexcharts/ssr'
const svg = await ApexCharts.renderToString(options)
// On client (for hydration):
import ApexCharts from 'apexcharts' // or 'apexcharts/client'
ApexCharts.hydrate(document.querySelector('#chart'))
Pitfall 16: updateOptions vs updateSeries vs appendData
❌ WRONG — full updateOptions just to change data:
chart.updateOptions({ series: [{ data: newData }] })
✅ CORRECT — use the right method:
// Replace all series data (most common)
await chart.updateSeries([{ name: 'Sales', data: newData }])
// Add data points to existing series (real-time streaming)
await chart.appendData([{ data: [newPoint] }])
// Change config (title, colors, axis, etc.)
await chart.updateOptions({ title: { text: 'New Title' } })
7. API Methods Quick Reference
Instance Methods
| Method | Description |
|---|---|
render() |
Renders the chart. Returns Promise<ApexCharts>. |
destroy() |
Destroys chart instance and removes DOM elements. |
updateOptions(options, redraw?, animate?, updateSyncedCharts?) |
Merges new options and re-renders. Returns Promise. |
updateSeries(newSeries, animate?) |
Replaces series data. Returns Promise. |
appendSeries(newSeries, animate?) |
Appends a new series to existing ones. Returns Promise. |
appendData(newData) |
Appends data points to each series. Returns Promise. |
toggleSeries(seriesName) |
Show/hide series by name. |
showSeries(seriesName) |
Show a hidden series. |
hideSeries(seriesName) |
Hide a visible series. |
resetSeries(shouldUpdateChart?, shouldResetZoom?) |
Resets to initial series data. |
zoomX(min, max) |
Programmatically zoom x-axis. |
addXaxisAnnotation(opts) |
Add x-axis annotation dynamically. |
addYaxisAnnotation(opts) |
Add y-axis annotation dynamically. |
addPointAnnotation(opts) |
Add point annotation dynamically. |
removeAnnotation(id) |
Remove annotation by id. |
clearAnnotations() |
Remove all annotations. |
dataURI(options?) |
Export chart as data URI. Returns Promise. |
getSvgString(scale?) |
Get chart SVG markup. Returns Promise<string>. |
exportToCSV(options?) |
Trigger CSV download. |
setLocale(localeName) |
Switch locale. |
toggleDataPointSelection(seriesIndex, dataPointIndex?) |
Select/deselect data point. |
getState() |
Returns snapshot of chart state. |
addEventListener(name, handler) |
Subscribe to chart event. |
removeEventListener(name, handler) |
Unsubscribe from chart event. |
Static Methods
| Method | Description |
|---|---|
ApexCharts.exec(chartID, fn, ...args) |
Call method on chart by its chart.id. |
ApexCharts.getChartByID(chartID) |
Get chart instance by id. |
ApexCharts.merge(target, source) |
Deep-merge objects. |
ApexCharts.use(typeMap) |
Register chart type constructors (tree-shaking). |
ApexCharts.registerFeatures(featureMap) |
Register optional feature modules. |
SSR Static Methods (available with apexcharts/ssr)
| Method | Description |
|---|---|
ApexCharts.renderToString(options) |
Render chart to SVG string (Node.js). |
ApexCharts.renderToHTML(options) |
Render chart to HTML string with wrapper (Node.js). |
ApexCharts.hydrate(element) |
Hydrate server-rendered chart (browser). |
ApexCharts.hydrateAll() |
Hydrate all server-rendered charts on page. |
ApexCharts.isHydrated(element) |
Check if element is already hydrated. |
8. Chart Events
{
chart: {
events: {
// Lifecycle
beforeMount: (chart, options) => {},
mounted: (chart, options) => {},
updated: (chart, options) => {},
animationEnd: (chart, options) => {},
// User interaction
click: (event, chart, options) => {},
mouseMove: (event, chart, options) => {},
mouseLeave: (event, chart, options) => {},
legendClick: (chart, seriesIndex, options) => {},
markerClick: (event, chart, options) => {},
xAxisLabelClick: (event, chart, options) => {},
// Data point events
dataPointSelection: (event, chart, options) => {},
dataPointMouseEnter: (event, chart, options) => {},
dataPointMouseLeave: (event, chart, options) => {},
// Zoom & pan
beforeZoom: (chart, { xaxis }) => {}, // return false to cancel
zoomed: (chart, { xaxis }) => {},
beforeResetZoom: (chart, options) => {}, // return false to cancel
scrolled: (chart, { xaxis }) => {},
selection: (chart, { xaxis, yaxis }) => {},
}
}
}
9. Reference Routing Table
For detailed chart-family-specific options, data format variants, and full working examples, refer to:
| Topic | Reference File |
|---|---|
| Line, Area, Scatter, Bubble, Range Area | references/cartesian-charts.md |
| Bar, Column, Range Bar, Timeline/Gantt | references/bar-charts.md |
| Candlestick, Box Plot | references/financial-charts.md |
| Pie, Donut, Polar Area, Radial Bar | references/circular-charts.md |
| Heatmap, Treemap | references/grid-charts.md |
| Radar | references/radar-charts.md |
| Tree-shaking, Bundle optimization | references/tree-shaking.md |
| Server-side rendering, Hydration | references/ssr.md |
| React, Vue, Angular integration | references/framework-wrappers.md |