COORDIATION CHARTS · OPEN-CODE COMPONENTS
Data, with dimension.
Interactive charts that belong in your product. Start with a working recipe, explore the options, then take the source into your own application.
The CSS core stays runtime-free. These optional React components use Apache ECharts 5.6 for 2D and ECharts GL 2.0.9 for 3D. They are not a new rendering engine and are not bundled into the CSS core.
Make the data speak.
35 working recipes. One editable component API.
Options apply where supported by the selected chart. Reduced-motion preferences override animations.
Illustrative data. Hover or tap a mark for values; click legend items to filter series.
Chart loads when it enters view. Data is available below.
View accessible data
| Day | Current | Previous |
|---|---|---|
| Mon | 24 | 16 |
| Tue | 38 | 25 |
| Wed | 31 | 20 |
| Thu | 58 | 38 |
| Fri | 46 | 30 |
| Sat | 70 | 46 |
| Sun | 62 | 40 |
SVG · RESPONSIVE RENDERING Example data, not live metrics
Inspect the current option code
// InteractiveChart from your installed components/ui source
const option = {
"color": [
"#e04419",
"#2563eb",
"#137c66",
"#8556b5",
"#b37212",
"#555e6f",
"#c33770"
],
"backgroundColor": "#fff",
"animationDuration": 750,
"animationDurationUpdate": 750,
"title": {
"show": true,
"text": "Grouped bar chart",
"subtext": "Illustrative data · Coordiation Charts",
"left": 12,
"textStyle": {
"fontSize": 18,
"color": "#151515"
},
"subtextStyle": {
"color": "#626262"
}
},
"tooltip": {
"show": true,
"trigger": "item",
"renderMode": "richText",
"confine": true
},
"legend": {
"show": true,
"bottom": 0,
"type": "scroll"
},
"grid": {
"top": 85,
"left": 18,
"right": 22,
"bottom": 55,
"containLabel": true
},
"aria": {
"enabled": true,
"decal": {
"show": true
}
},
"xAxis": {
"type": "category",
"data": [
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun"
]
},
"yAxis": {
"type": "value",
"splitLine": {
"show": true
}
},
"series": [
{
"name": "Current",
"type": "bar",
"data": [
24,
38,
31,
58,
46,
70,
62
],
"barMaxWidth": 48,
"emphasis": {
"focus": "series"
}
},
{
"name": "Previous",
"type": "bar",
"data": [
16,
25,
20,
38,
30,
46,
40
]
}
]
};Installation
Use React 18+ with Coordiation CSS configured. This React adapter is optional; non-React applications can use ECharts directly with Coordiation styling. The existing static Chart container is unchanged.
npm install echarts@5.6.0
npx @coordiation/cli@next add component interactive-chartnpm install echarts@5.6.0 echarts-gl@2.0.9
npx @coordiation/cli@next add component chart-3dChoose the 3D installer first if you need both: it includes the base files. If those files already exist, preserve your edits and add only the missing 3D file from the registry. Install engine dependencies explicitly; the source installer does not replace your package manager.
"use client";
import { InteractiveChart } from "@/components/ui/interactive-chart";
import { chartRecipe } from "@/components/ui/chart-recipes";
export default function WeeklyChart() {
const { option, rows, headers, note } = chartRecipe("Grouped bar");
return <InteractiveChart title="Weekly activity" description={note}
option={option} height={360} table={
<table><caption>Weekly activity</caption>
<thead><tr>{headers.map(h => <th key={h} scope="col">{h}</th>)}</tr></thead>
<tbody>{rows.map((row, i) => <tr key={i}>
{row.map((cell, j) => <td key={j}>{cell}</td>)}
</tr>)}</tbody>
</table>
} />;
}Engines initialize after the chart enters the viewport. For Next.js, keep options containing functions inside a client component. Server-rendered captions and data tables remain readable before the engine loads.
Inspect 2D source JSON · Inspect 3D source JSON · AI-readable manifest
Bar Charts
Compare categories using vertical, horizontal, grouped, stacked or waterfall bars. Use a zero baseline for magnitude comparisons. A logarithmic bar scale changes that interpretation and is only valid for positive data.
chartRecipe("Bar");
chartRecipe("Horizontal bar");
chartRecipe("Grouped bar");
chartRecipe("Stacked bar");
chartRecipe("Waterfall");
// Raw options: { xAxis: { type: "category", data: ["A", "B"] },
// yAxis: { type: "value" }, series: [{ type: "bar", data: [24, 38] }] }Line Charts
Use lines for ordered observations. Smooth lines are a visual interpolation, not measured intermediate values. Step lines represent discrete changes; use null for a missing observation rather than inventing a zero.
series: [{ type: "line", data: [12, 30, null, 24],
smooth: false, connectNulls: false, symbolSize: 8,
// step: "middle" // Enable for stepped data
}]Other charts
The playground includes 35 explicit recipes. This is a broad catalog, not a claim to include every possible visualization.
Comparison & relationships
Mixed bar/line, scatter, bubble, radar, polar bar, graph and parallel coordinates.
Composition & hierarchy
Pie, doughnut, rose, treemap, sunburst and collapsible tree.
Distribution & time
Heatmap, calendar heatmap, boxplot, candlestick and theme river.
Flow & progress
Sankey, funnel and gauge, alongside waterfall and stacked series.
Boxplots require min/Q1/median/Q3/max in that order; candlesticks use open/close/low/high. Scatter uses [x, y], bubble adds a size dimension, hierarchies use nested children, and Sankey uses named nodes with source/target/value links. See the preview’s data table and option code for each format.
Geographic maps require your own licensed GeoJSON and registration. Gantt, violin, chord and domain-specific custom series are not supplied as recipes in this release. Do not substitute another chart and label it as one of these.
Area charts
Area and stacked area show how magnitude evolves. Keep a common stack identifier for additive series and use opacity so overlapping series remain legible.
series: [
{ name: "Direct", type: "line", stack: "total", areaStyle: { opacity: 0.2 }, data: [20, 30, 40] },
{ name: "Referral", type: "line", stack: "total", areaStyle: { opacity: 0.2 }, data: [10, 15, 20] }
]Scales
ECharts uses category, value (linear), time and log axes. The playground exposes linear/log for compatible charts; heatmap, calendar, polar and 3D use their own coordinate systems.
xAxis: { type: "time" },
yAxis: { type: "log", logBase: 10, min: 1 },
series: [{ type: "line", data: [["2026-06-01", 10], ["2026-06-02", 100]] }]Never feed zero or negative values into a logarithmic scale. Use timestamped points for irregular intervals instead of evenly spaced category labels.
Scale Options
Control bounds, intervals, labels, grid lines, inversion and zoom. Set units in labels and the accessible table. Match the axis index when combining multiple scales.
yAxis: { type: "value", min: 0, max: 100, interval: 25,
name: "Completion (%)", inverse: false,
axisLabel: { formatter: "{value}%" }, splitLine: { show: true }
},
dataZoom: [{ type: "inside" }, { type: "slider" }]Legend
Named series and pie slices appear in the legend. Click a legend item to toggle it; use scrolling legends for many items. The data table remains an independent keyboard-accessible source.
legend: { show: true, type: "scroll", bottom: 0,
selected: { Current: true, Previous: true }
}Title
The component’s required title labels the figure. The optional engine title is drawn inside the chart and can be positioned separately.
title: { show: true, text: "Weekly activity", left: 12,
textStyle: { fontSize: 18, color: "#151515" }
}Subtitle
Use title.subtext for period, units or source. Use the component’s description for an accessible narrative or the main takeaway.
title: { text: "Weekly activity", subtext: "June 2026 · visits",
subtextStyle: { color: "#626262" }
}Tooltip
Hover or tap a data mark. Use item tooltips for individual points or axis tooltips for shared category comparisons. Tooltips supplement, never replace, readable data.
tooltip: { show: true, trigger: "axis", renderMode: "richText",
confine: true, axisPointer: { type: "cross" },
valueFormatter: value => String(value) + " visits"
}Keep untrusted labels as text. Avoid HTML formatters with unsanitized values. The supplied recipes use rich-text rendering rather than injecting tooltip HTML.
Scriptable Options
Pass trusted JavaScript callbacks to supported options such as color, symbol size, label formatters and animation delay. These are ECharts callbacks, not Chart.js’s context API. The playground’s scriptable control colors values of at least 50 green.
itemStyle: {
color: point => Number(point.value) >= 50 ? "#137c66" : "#e04419"
},
animationDelay: index => Math.min(index * 40, 500)
// Bubble: symbolSize: value => Math.sqrt(value[2]) * 3Do not evaluate user-supplied code or deserialize functions from JSON. Functions belong in reviewed application source; validate remote data separately.
Animations
Entrance runs when the chart first enters view. Updates animate when options change; Replay entrance remounts the preview. The wrapper responds to the operating system’s reduced-motion setting, including changes while the page is open.
const option = { animationDuration: 750,
animationDurationUpdate: 400, animationEasing: "cubicOut",
animationDelay: index => Math.min(index * 40, 500),
// ...axes and series
};
// <InteractiveChart animate={false} ... /> disables wrapper animations.Different engines and series support different transitions. WebGL updates are not guaranteed to match SVG line/bar animations. Avoid continuous motion and use no auto-rotation by default.
3D charts
Bar, scatter, line and surface recipes use a real WebGL scene, not a CSS perspective effect. Drag to rotate and scroll to zoom. The GL extension loads only when a 3D chart is mounted and visible.
import { Chart3D } from "@/components/ui/chart-3d";
import { chartRecipe } from "@/components/ui/chart-recipes";
const { option, rows, headers } = chartRecipe("3D surface");
// Render <Chart3D title="Surface" option={option} table={yourDataTable} />If WebGL is unavailable or the engine fails, the wrapper offers retry and retains the table. 3D can distort magnitude comparisons: prefer 2D for precise business reporting. Globe and geographic 3D require additional geographic assets and are not included here.
Accessibility, lifecycle & performance
Always provide a semantic table with units and a caption. Native details/summary keeps the data keyboard-accessible. SVG/WebGL marks do not provide a complete keyboard interaction model; equivalent data is available through the table. Do not rely on color alone.
The wrapper resizes with its container and disposes observers and engine instances on unmount. Use a bounded height, sample or aggregate large datasets, and avoid mounting dozens of WebGL canvases at once. The main engine is lazy-loaded but contains the full ECharts catalog; it is not a tiny dependency. For specialized production bundles, replace the dynamic import with a tree-shaken selection from ECharts core.
Apache ECharts option reference · ECharts GL documentation and compatibility
