Updating, styling and interaction
Mutate the data then call update, control every visual with dataset and option properties, and keep the chart usable on small screens.
Updating data
// mutate the data, then re-render
chart.data.labels.push('May');
chart.data.datasets.forEach((ds) => ds.data.push(random()));
chart.update();
// update with no animation - correct for streaming or live dashboards
chart.data.datasets[0].data[0] = 42;
chart.update('none');
// drop the oldest point and keep a rolling window
chart.data.labels.shift();
chart.data.datasets.forEach((ds) => ds.data.shift());
// replace the whole dataset, then re-render
chart.data.datasets = buildDatasets(response);
chart.update();
// restore the original animation state and re-run entry animations
chart.reset();
// release the canvas and its listeners when the widget is removed
chart.destroy();| Call | What it does |
|---|---|
update() | Recomputes scales and redraws with animation |
update('none') | Same, but skips animation — the choice for live data |
update(mode) | Accepts any animation mode name, for example 'active' |
reset() | Returns the chart to its original data and state |
resize(w, h) | Forces a size; pass nothing to re-measure the parent |
destroy() | Detaches observers and clears the canvas |
toBase64Image() | Returns a PNG data URL of the current frame |
- Chart.js 2 had
addDataandremoveData; version 3 removed them. Mutatedataand callupdate(). - Batching matters: push every point you have, then call
update()once instead of per point. destroy()in the framework unmount path prevents listeners and animation frames leaking between route changes.
Styling options
| Property | Applies to | Notes |
|---|---|---|
backgroundColor | All | String or array; bars and arcs fill with it |
borderColor / borderWidth | All | Also drives line stroke width |
borderRadius | bar | Rounds bar corners; a number or an object per corner |
tension | line | 0 is straight, around 0.4 is the usual curve |
fill | line | true, 'origin' or { target: '1' } to fill between datasets |
pointRadius / pointHoverRadius | line, scatter | Set to 0 to hide markers on dense lines |
spanGaps | line | Connects across null values instead of breaking |
cutout | doughnut | Percentage of the radius left hollow |
animation.duration | All | Milliseconds; 0 disables animation entirely |
options: {
animation: { duration: 400, easing: 'easeOutQuart' },
plugins: {
legend: {
position: 'bottom',
labels: { usePointStyle: true, boxWidth: 8, padding: 16 }
},
tooltip: {
callbacks: {
label: (ctx) => ctx.dataset.label + ': ' + ctx.parsed.y + ' units',
title: (items) => 'Week of ' + items[0].label
}
}
},
scales: {
x: { grid: { display: false } },
y: { border: { dash: [4, 4] } }
}
}Responsive layout and interaction
options: {
responsive: true, // default: re-render when the container resizes
maintainAspectRatio: false, // fill the container height instead of a fixed ratio
onResize: (chart, size) => {
chart.options.plugins.legend.display = size.width > 480;
},
interaction: { mode: 'index', intersect: false },
onClick: (event, elements, chart) => {
if (elements.length) drillDown(elements[0].index);
},
plugins: {
decimation: { enabled: true, algorithm: 'lttb', samples: 500 }
}
}interaction.mode: 'index'withintersect: falseshows one tooltip per x position — far friendlier than hunting individual points.- The
decimationplugin replaces thousands of points with a visually faithful subset; it requiresparsing: falseand a linear x scale. - For React and Vue, create the chart after the canvas is in the DOM and destroy it on unmount; reusing one instance across renders causes double-registered listeners.
⚠️
Never re-create the chart on every data change. Constructing a second
Chart on the same canvas leaves the first instance observing the same element, which shows up as flicker, duplicated tooltips and steadily rising memory.FAQ
How do I make a custom HTML tooltip?
Disable the built-in one and use
plugins.tooltip.external: keep a reference to a positioned element, read tooltipModel.body and place it near tooltipModel.caretX/Y on each call.Why is my line chart jagged or wrong after an update?
Usually the labels and the data arrays drifted out of sync — one got pushed without the other. Keep labels and every dataset the same length, or switch to
{ x, y } points so the data carries its own axis values.Related
Chart types and datasets Interaction, resize and data updates
Last refreshed 2026-09-18.