This guide distills the full Chart.js v4 API, covering installation, core Chart lifecycle methods, dataset structure, scales, plugin extensibility, and performance strategies. The content targets developers migrating from v2 / v3 as well as newcomers seeking a reliable canvas‑based chart solution.
Current stable version: 4.4.9
(released 17 days
ago)
Use npm for bundlers (webpack
, Vite
) or the global CDN for quick prototyping:
# npm
npm install chart.js@^4
# ESM import
import { Chart, registerables } from 'chart.js';
Chart.register(...registerables);
<!-- CDN — tree‑shakable ESM -->
<script type="module"
src="https://cdn.jsdelivr.net/npm/chart.js"></script>
// HTML canvas
<canvas id="sales"></canvas>
// JS
const ctx = document.getElementById('sales');
new Chart(ctx, {
type: 'bar',
data: {
labels: ['Q1','Q2','Q3','Q4'],
datasets: [{ label:'2025 sales', data:[4,6,5,8] }]
}
});
Tip: From v4 every component (controller, scale, element) is
tree‑shakable. Always call Chart.register() (or
Chart.registerables
) to avoid huge bundles in frameworks such as
React.
bar
, line
, scatter
pie
, doughnut
, polarArea
Type controllers are modular; only import those you need to keep bundle size minimal.
{
label: 'Series A',
data: [88, 92, 81, 95],
backgroundColor: 'rgba(54, 162, 235, 0.5)',
borderWidth: 1
}
Datasets support both primitive [y]
and object
{ x, y }
formats. For bubble
, you may add
r
(radius). Tooltips automatically map fields like
x
, y
, r
.
myChart.data.datasets[0].data[2] = 50;
myChart.update('active'); // animates changes
The update() method triggers a full re‑render, reflowing scales, legends and elements.
import { defaults } from 'chart.js';
defaults.font.family = 'Inter, sans‑serif';
defaults.color = '#444';
new Chart(ctx,{ /* … */
options:{
elements:{ line:{ tension:0.3 } },
plugins:{ legend:{ position:'bottom' } }
}
});
Options cascade: Dataset‑level ⇢ Chart‑level ⇢ Global defaults.
Chart.js v4 provides composable scales like CategoryScale, LinearScale, LogarithmicScale, TimeScale and an auto layout engine that reserves padding for legends / titles.
options:{
scales:{
y:{ type:'linear', beginAtZero:true, grace:'10%' },
x:{ type:'time', time:{ unit:'month' } }
}
}
Events such as mousemove
, click
and custom
accessibility events are routed through the internal
EventHandler. Override tooltip callbacks to
format labels or implement hit testing on complex visualisations.
options:{
onClick:(evt, elements, chart)=>{
if(elements.length){
console.log(elements[0].index);
}
},
interaction:{ mode:'nearest', axis:'x', intersect:false }
}
The animation engine supports per‑property easing, scripted animations
and performance‑friendly Decimation
plugins for large
datasets.
options:{
animation:{
duration: 1500,
easing: 'easeOutQuart',
onProgress:(ctx)=>{/* ... */}
}
}
Plugins hook into beforeInit
, afterDraw
,
afterDatasetsDraw
, and more. Global plugins are registered
via Chart.register(MyPlugin), while scoped
plugins sit in options.plugins
.
const tooltipBg = {
id:'tooltipBg',
beforeDraw(chart,args,opts){
const {ctx,tooltip} = chart;
if(!tooltip.opacity) return;
ctx.fillStyle = opts.color || '#0004';
ctx.fillRect(tooltip.caretX‑4, tooltip.caretY‑4, tooltip.width+8, tooltip.height+8);
}
};
Chart.register(tooltipBg);
Note: A plugin is simply an object adhering to the
Plugin
interface. You can tree‑shake unused hooks in modern
builds.
import Chart from 'chart.js/auto'
with explicit
component registration.See the full breaking‑changes list in the official migration notes.
decimation
plugins (e.g. LTTB) for large series.update('none')
to skip animations.data
in place, then a single
chart.update().
• Official Docs – chartjs.org/docs
• GitHub Issues & Discussions
• Community plugins (chartjs-plugin-annotation
,
chartjs-plugin-zoom
)
• Stack Overflow [chart.js]
tag