npx skills add ...
npx skills add sentimony/skills --skill echarts
You MUST use this when building, styling, debugging, or optimizing Apache ECharts charts in JavaScript, React, or Vue - setup, lifecycle, responsive resizing, theming, large datasets, streaming, SSR, and symptoms like a blank chart or broken resize. Not for choosing chart types or for other charting libraries.
npx skills add sentimony/skills --skill echarts
Use this skill to build, audit, or fix Apache ECharts charts without turning the task into an option-reference lookup. Match the project's existing setup first; only introduce wrappers or new dependencies when the project has none.
echarts.init runs; a chart in a display:none or unmounted tab renders blank.init per container, resize() on container size change, dispose() on unmount. Wrappers handle this; hand-rolled code must.setOption: default merge mode for incremental updates (streaming, new data); notMerge: true when the chart type or structure changes.Tree-shakeable imports for production bundles:
A missing registration fails at runtime with a console error naming the missing chart/component; register it, do not switch to full import to silence the error. It is a console.error, not a thrown exception, so unit tests pass silently over it; catch it by asserting on the console or the rendered output.
With multiple chart components in one codebase, prefer a shared registration module (one echarts.use([...]) call imported everywhere) over per-component use lists; per-component lists drift out of sync and hide missing registrations until a component renders alone. Deliberate feature-specific registration in code-split routes is a valid exception for lazy-loaded dashboards.
Type imports: import type { ... } from 'echarts' is erased at compile time and does not affect the bundle; only value imports from the root package pull everything in. Some types (XAXisComponentOption, DefaultLabelFormatterCallbackParams) are exported only from the root, so mixing import type from 'echarts' with values from 'echarts/core' is normal; prefer ComposeOption from 'echarts/core' for option types:
chart.resize() from a ResizeObserver on the container; call chart.dispose() before removing the container.option as a prop; use notMerge prop when replacing structure; get the instance via ref.getEchartsInstance() only for imperative needs (streaming setOption, dispatchAction).init in an effect, dispose in its cleanup; keep option updates in a separate effect so the chart is not re-created on every render.:option binding with autoresize; access the instance via template ref for dispatchAction. Pass :update-options="{ notMerge: true }" for structural option changes (chart type, series count, removing axes/series); merge mode keeps stale series. Switch themes via the theme prop or THEME_KEY injection, not update-options (on older ECharts/vue-echarts versions, remount/re-init instead). Use the group prop to link charts (equivalent to echarts.connect).echarts.init twice on the same DOM node; reuse the instance or dispose first (echarts.getInstanceByDom to check).dataset component (source + encode) when multiple series or charts share one table of data; use per-series data for simple single-series charts.xAxis: { type: 'time' } with [timestamp, value] pairs instead of pre-formatting date strings into a category axis.axisLabel.interval/rotate deliberately instead of accepting overlap.trigger: 'axis' for line/bar time series, trigger: 'item' for pie/scatter/map.valueFormatter or tooltip.formatter for units; keep number formatting in one shared helper when the dashboard has many charts.formatter output is injected as HTML: escape untrusted data (series names, user-generated labels) with a shared escape helper, or use tooltip.renderMode: 'richText' to opt out of HTML entirely.large: true and sampling: 'lttb' on the series; turn off animation for initial render of big datasets.echarts-gl (WebGL), a separate dependency; add it only when actually needed.setOption({ series: [{ data }] }) on the existing instance (merge mode); do not re-init or pass notMerge per tick.ResizeObserver/resize handler and use echarts.connect for linked tooltips/dataZoom instead of duplicating handlers. connect is also a UX feature for dashboards: chart.group = 'name'; echarts.connect('name') (or the vue-echarts group prop) syncs tooltips and dataZoom across related charts. Only link charts with compatible axis semantics (same x-axis type and domain); a chart with a different axis belongs in its own group or unlinked.echarts.registerTheme('name', themeObject)) and pass the name to every init; do not copy color arrays into each chart's option.init(el, null, ...) plus a registered dark theme, or darkMode: true in the option. Switch themes at runtime with chart.setTheme(...) (ECharts 6) or the vue-echarts theme prop; on ECharts 5 themes are fixed at init time; re-init (dispose + init) there.echarts.init(null, null, { renderer: 'svg', ssr: true, width, height }) then renderToSVGString() - Node only, no DOM needed.echarts.use([...]) registration points covering the same set; a narrower server-side list silently renders without the missing components.toolbox.feature.saveAsImage, or call chart.getDataURL({ pixelRatio: 2 }) programmatically.grid.containLabel is deprecated. The semantics-preserving migration is containLabel: true → { outerBoundsMode: 'same', outerBoundsContain: 'axisLabel' }; set grid.outerBounds only when you need a custom constraint rect (it is a separate part of the new layout API). The legacy behavior still works only if LegacyGridContainLabel (from 'echarts/features') is registered; treat remaining containLabel: true usages as tech debt when auditing.import 'echarts/theme/v5' and pass 'v5' as the theme to init.grid.outerBoundsMode: 'none' and xAxis/yAxis.nameMoveOverlap: false when pixel-parity with v5 matters.node_modules/echarts/package.json) before recommending options; deprecations surface as console warnings, not errors.For a code-and-browser audit, read references/audit.md before writing findings. It is the required full checklist for dashboard growth, tree-shaken registrations, interactive state, HTML tooltip trust, large-data cardinality, zero-size failures, and browser evidence. When the chart instance is not reachable from the page (production bundle, wrapper without an exposed instance), section 4 and section 8 of the reference describe DOM proxies that stand in for getOption().
Quick triage still starts with the shared registration module, lifecycle ownership, structural setOption updates, root value imports, and ECharts-version migration debt. Treat repeated formatter/options as extraction debt; centralized design tokens passed directly to options are a valid alternative to registerTheme when that is the project's deliberate convention.
resize().notMerge: true when removing series or changing chart type.notMerge: true can reset interactive state, depending on the wrapper, versions, and update path. Capture the state you need to survive (chart.getOption().legend[0].selected, the dataZoom range) and pass it back, or give it an explicit app-side owner. Do not report a reset from static inspection alone; prove it on the installed ECharts/wrapper versions. The ECharts instance is a valid owner for session-only state when browser evidence shows it survives and the product does not require it to survive a remount or navigation.notMerge: true everywhere: forfeits ECharts' diff optimization and risks resetting legend/dataZoom selection on structural updates. Reserve it for structural changes (chart type, series count, removed axes/series); keep merge mode for data-only updates.echarts.use([...]).dispose() runs in unmount cleanup.resize event never fired; observe the container (ResizeObserver / autoresize), not the window.tooltip.confine: true or appendToBody-style tooltip.appendTo when the chart sits in an overflow-hidden container.animation: false, sampling: 'lttb', large: true before reaching for WebGL.examples/vanilla_line.html - Vanilla JS time-series line chart with resize handlingexamples/react_chart.tsx - React component with tree-shaken imports and echarts-for-reactexamples/vue_chart.vue - Vue 3 component using vue-echarts with autoresizenpm install echarts # core library (always)
npm install echarts-for-react # React wrapper (optional)
npm install vue-echarts # Vue 3 wrapper (optional)import * as echarts from 'echarts/core';
import { LineChart, BarChart } from 'echarts/charts';
import { GridComponent, TooltipComponent, DataZoomComponent } from 'echarts/components';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([LineChart, BarChart, GridComponent, TooltipComponent, DataZoomComponent, CanvasRenderer]);import type { ComposeOption } from 'echarts/core';
import type { LineSeriesOption } from 'echarts/charts';
import type { GridComponentOption, TooltipComponentOption } from 'echarts/components';
type ChartOption = ComposeOption<LineSeriesOption | GridComponentOption | TooltipComponentOption>;