ECharts cheat sheet

A scannable ECharts reference: 20 short snippets across 8 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Option configurationA dataset keeps rows in one place and lets each series declare which column is the dimension and which are the valueslesson
Common chart typesLine, bar and pie as the baseline, the wider family of series types, and the per-series options that change how datalesson
Interaction, resize and data updatesListening to window.resize misses every layout change that is not a viewport change: sidebars, split panes and CSS gridlesson
Getting started: install, init and lifecycleChoose between the CDN build and tree-shaken ESM imports, pick canvas or SVG rendering, size the container correctlylesson
Styling, themes and dark modeThe practical rule for a design system: describe everything shared in a theme object, and keep only per-chart variationlesson
Tooltips, legends, labels and visual mapsWrite formatter callbacks that produce useful tooltips, manage label overlap, and drive colour from data withlesson
ECharts in React, Vue and AngularIn every framework the same three rules apply: create the chart after the DOM exists, store the instance outside thelesson
Accessibility, export and printingGenerate a text description with the aria option, add decal patterns so colour is not the only channel, export imageslesson

Quick snippets

Option configuration

The option tree

chart.setOption({
  title: { text: 'Weekly signups', left: 'center' },
  tooltip: { trigger: 'axis' },
  legend: { bottom: 0 },
  grid: { left: 48, right: 24, top: 56, bottom: 48 },
  xAxis: { type: 'category', boundaryGap: false },
  yAxis: { type: 'value', name: 'users' },
  series: [
    { name: 'Free', type: 'line', areaStyle: {}, smooth: true, data: [820, 932, 901, 1290] },
    { name: 'Paid', type: 'line', areaStyle: {}, smooth: true, data: [120, 132, 141, 154] }
  ]
});

Initialise and setOption

<div id="main" style="width: 100%; height: 360px;"></div>
<script type="module">
  import * as echarts from 'https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.esm.min.js';

  const chart = echarts.init(document.getElementById('main'), null, {
    renderer: 'canvas',      // or 'svg' for large static dashboards and print
    useDirtyRect: true       // cheaper partial repaints while animating
  });

  chart.setOption({
    xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu'] },
    yAxis: { type: 'value' },

… 6 more lines in the full lesson.

Dataset and encode

chart.setOption({
  dataset: {
    source: [
      ['week', 'free', 'paid'],
      ['W1', 820, 120],
      ['W2', 932, 132],
      ['W3', 901, 141],
      ['W4', 1290, 154]
    ]
  },
  xAxis: { type: 'category' },
  yAxis: { type: 'value' },

… 8 more lines in the full lesson.

Full lesson: Option configuration →

Common chart types

Line, bar and pie

chart.setOption({
  tooltip: { trigger: 'axis' },
  legend: { bottom: 0 },
  xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'] },
  yAxis: { type: 'value' },
  series: [
    { name: 'Revenue', type: 'bar', data: [120, 200, 150, 80], barMaxWidth: 32 },
    { name: 'Target', type: 'line', data: [110, 180, 170, 120], smooth: true },
    { name: 'Mix', type: 'pie', radius: ['45%', '70%'], center: ['82%', '38%'],
      data: [
        { value: 1048, name: 'Direct' },
        { value: 735, name: 'Search' },

… 4 more lines in the full lesson.

Beyond the basics

// scatter with an intensity legend
chart.setOption({
  xAxis: {},
  yAxis: {},
  visualMap: {
    min: 0, max: 100, dimension: 2, calculable: true,
    inRange: { color: ['#bfdbfe', '#1d4ed8'] }
  },
  series: [{
    type: 'scatter',
    symbolSize: (data) => Math.sqrt(data[2]) * 2,
    data: [[10, 8, 20], [15, 20, 55], [22, 14, 90]]

… 2 more lines in the full lesson.

Per-series options that matter

series: [
  { name: 'Direct', type: 'bar', stack: 'traffic', data: [320, 302, 301] },
  { name: 'Search', type: 'bar', stack: 'traffic', data: [120, 132, 101] },
  { name: 'Rate', type: 'line', yAxisIndex: 1, smooth: true,
    data: [0.12, 0.16, 0.14], label: { show: true, formatter: '{c}' } },
  {
    name: 'Orders',
    type: 'bar',
    barGap: '10%',
    barCategoryGap: '30%',
    emphasis: { focus: 'series' },
    data: [90, 110, 95]

… 2 more lines in the full lesson.

Full lesson: Common chart types →

Interaction, resize and data updates

Events and actions

// listen: params carries the data point and the series that produced it
chart.on('click', (params) => {
  console.log(params.seriesName, params.name, params.value, params.dataIndex);
  openDetail(params.data.id);
});

chart.on('legendselectchanged', (params) => {
  saveVisibility(params.selected);      // { Free: false, Paid: true }
});

// dispatch: drive the chart programmatically
chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: 3 });

… 3 more lines in the full lesson.

Responsive resize

// simplest correct approach: observe the container, not the window
const ro = new ResizeObserver(() => chart.resize());
ro.observe(document.getElementById('main'));

// stop observing when the chart is torn down
// ro.disconnect(); chart.dispose();

// option-level responsiveness: overrides keyed on container width
chart.setOption({
  baseOption: {
    legend: { bottom: 0 },
    series: [{ type: 'line', symbol: 'circle' }]

… 12 more lines in the full lesson.

Updating data

// merge (default): matched series are updated in place
chart.setOption({ series: [{ data: nextValues }] });

// explicitly replace one component type instead of merging
chart.setOption({ series: [{ data: nextValues }] }, { replaceMerge: ['series'] });

// full rebuild: nothing from the previous option survives
chart.setOption(freshOption, { notMerge: true });

// defer the render to the next frame when several updates arrive together
chart.setOption(patch, { lazyUpdate: true });

… 2 more lines in the full lesson.

Full lesson: Interaction, resize and data updates →

Getting started: install, init and lifecycle

Install and import

npm install echarts
# the full build is about 1 MB minified; the tree-shaken path is far smaller

init, container sizing and rendering mode

<div id="revenue" style="width: 100%; height: 360px;"></div>

Install and import

// Option A: everything, one import. Convenient, largest bundle.
import * as echarts from 'echarts';

// Option B: compose the exact chart you need. This is the production path.
import * as echarts from 'echarts/core';
import { LineChart, BarChart } from 'echarts/charts';
import {
  GridComponent, TooltipComponent, LegendComponent,
  DataZoomComponent, TitleComponent, MarkLineComponent
} from 'echarts/components';
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';

… 12 more lines in the full lesson.

Full lesson: Getting started: install, init and lifecycle →

Styling, themes and dark mode

Switching at runtime

// For a light/dark palette that changes together with the site, use a
// dynamic theme: a function that returns the theme based on a value.
echarts.registerTheme('adaptive', (value) => {
  const dark = value === 'dark';
  return {
    color: dark
      ? ['#a78bfa', '#38bdf8', '#fbbf24', '#34d399', '#f87171']
      : ['#6d28d9', '#0ea5e9', '#f59e0b', '#10b981', '#ef4444'],
    textStyle: { color: dark ? '#e2e8f0' : '#0f172a' },
    valueAxis: {
      axisLabel: { color: dark ? '#94a3b8' : '#475569' },
      splitLine: { lineStyle: { color: dark ? '#1e293b' : '#e2e8f0' } }

… 12 more lines in the full lesson.

Switching at runtime

// When the site theme is already a set of CSS custom properties, read them
// and build the chart colours from the same tokens. One source of truth.
function themeFromCss(root = document.documentElement) {
  const styles = getComputedStyle(root);
  const token = (name, fallback) => styles.getPropertyValue(name).trim() || fallback;

  return {
    color: [
      token('--chart-1', '#6d28d9'),
      token('--chart-2', '#0ea5e9'),
      token('--chart-3', '#f59e0b')
    ],

… 16 more lines in the full lesson.

Overriding individual visuals

// Anything the theme sets can be overridden at the option level, and the
// option wins. This is how a single chart deviates from the house style.
const option = {
  color: ['#0f766e'],                       // override the palette for this chart
  textStyle: { fontFamily: 'Georgia, serif' },
  legend: { textStyle: { color: '#0f172a', fontWeight: 600 } },
  series: [{
    type: 'line',
    smooth: true,
    lineStyle: { width: 3, color: '#0f766e' },
    itemStyle: { color: '#0f766e', borderColor: '#fff', borderWidth: 2 },
    areaStyle: {

… 16 more lines in the full lesson.

Full lesson: Styling, themes and dark mode →

Tooltips, legends, labels and visual maps

visualMap, markLine and markArea

// A richer label formatter: rich text lets one label mix styles.
const richLabel = {
  label: {
    show: true,
    formatter: '{name|{b}}
{value|{c} ms}',
    rich: {
      name:  { color: '#64748b', fontSize: 11, lineHeight: 16 },
      value: { color: '#0f172a', fontSize: 14, fontWeight: 600, lineHeight: 20 }
    }
  }
};

… 9 more lines in the full lesson.

Full lesson: Tooltips, legends, labels and visual maps →

ECharts in React, Vue and Angular

Angular

// Server rendering: ECharts needs a DOM. Two workable approaches.
//
// 1. Skip the chart on the server and render it after hydration.
//    In Angular: afterNextRender, as above. In React: guard with a mounted flag.
//
// 2. Render the chart on the server and ship the SVG output as markup.
//    The chart is static until the client hydrates, but the layout is correct
//    on first paint and the data is crawlable.

// React: a mounted flag keeps the server output and the first client render identical.
import { useState, useEffect } from 'react';

… 7 more lines in the full lesson.

Full lesson: ECharts in React, Vue and Angular →

Accessibility, export and printing

Decal patterns and focus

/* Give the chart container a visible focus style and a sensible role. */
.chart-container:focus-visible {
  outline: 2px solid var(--brand, #6d28d9);
  outline-offset: 2px;
}

/* Never hide a chart from assistive tech with aria-hidden when it carries data. */
.chart-container { position: relative; }

/* Respect reduced motion: ECharts listens to its own option, not to CSS. */
@media (prefers-reduced-motion: reduce) {
  /* Nothing to do in CSS — set animation: false in the option instead. */

… 1 more lines in the full lesson.

Decal patterns and focus

// Honour the reduced-motion preference in the option itself.
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');

function animationOption(matches) {
  return matches
    ? { animation: false }
    : { animation: true, animationDuration: 400, animationEasing: 'cubicOut' };
}

chart.setOption({
  ...baseOption,
  ...animationOption(prefersReducedMotion.matches)

… 5 more lines in the full lesson.

Export and printing

// A print path that produces a usable page rather than a screenshot.
window.addEventListener('beforeprint', () => {
  // Re-render at a higher device pixel ratio so the printed output is sharp.
  chart.setOption({}, false);
  chart.resize({ width: 900, height: 500 });
});

window.addEventListener('afterprint', () => {
  chart.resize();                       // back to the container's size
});

// If the chart is off-screen when the user prints, it may never have rendered.

… 6 more lines in the full lesson.

Full lesson: Accessibility, export and printing →

FAQ

Is this ECharts cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 8 lessons of the ECharts course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full ECharts course — it carries the worked explanations, the edge cases and the exercises behind every line here.

HTML CSS JavaScript TypeScript HTML DOM AJAX

Last refreshed 2026-09-27.