This skill should be used when the user asks "Chart.js options", "Chart.js animations", "Chart.js legend", "Chart.js tooltip", "Chart.js title", "disable Chart.js animation", "customize Chart.js tooltip", "Chart.js responsive", "Chart.js aspect ratio", "Chart.js interactions", "Chart.js hover", "Chart.js click events", "Chart.js layout", "Chart.js padding", "Chart.js font", "Chart.js colors", "Chart.js external tooltip", "Chart.js custom legend", "Chart.js transitions", or needs help configuring Chart.js v4.5.1 options, plugins, and styling.
This skill inherits all available tools. When active, it can use any tool Claude has access to.
examples/custom-tooltip.htmlexamples/interactive-legend.htmlexamples/responsive-chart.htmlreferences/advanced-animations.mdreferences/legend-customization.mdreferences/tooltip-customization.mdComprehensive guide to configuring Chart.js options, animations, legends, tooltips, and interactions.
const config = {
type: 'line',
data: { /* datasets, labels */ },
options: {
responsive: true,
maintainAspectRatio: true,
aspectRatio: 2,
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
onClick: (event, elements, chart) => { /* handle click */ },
onHover: (event, elements, chart) => { /* handle hover */ },
plugins: {
legend: { /* legend options */ },
tooltip: { /* tooltip options */ },
title: { /* title options */ }
},
scales: { /* axis options */ },
animation: { /* animation options */ },
interaction: { /* interaction options */ },
layout: { /* layout options */ }
},
plugins: [] // Inline plugins
};
Namespace: options
| Option | Type | Default | Description |
|---|---|---|---|
responsive | boolean | true | Resize with container |
maintainAspectRatio | boolean | true | Keep aspect ratio |
aspectRatio | number | 2 (radial: 1) | Width/height ratio |
resizeDelay | number | 0 | Debounce resize (ms) |
onResize | function | null | Callback on resize |
Chart.js requires the container to be relatively positioned and dedicated to the chart canvas only:
<div class="chart-container" style="position: relative; height: 40vh; width: 80vw">
<canvas id="chart"></canvas>
</div>
To prevent overflow in flexbox/grid layouts, set min-width: 0 on the container:
<div class="grid-container" style="display: grid">
<div class="chart-container" style="min-width: 0">
<canvas id="chart"></canvas>
</div>
</div>
For fixed-size charts, set responsive: false and define canvas dimensions directly.
See examples/responsive-chart.html for complete responsive setup including print handling.
Namespace: options.plugins.legend
| Option | Type | Default | Description |
|---|---|---|---|
display | boolean | true | Show legend |
position | string | 'top' | top, bottom, left, right, chartArea |
align | string | 'center' | start, center, end |
reverse | boolean | false | Reverse order |
maxHeight | number | - | Maximum height (px) |
maxWidth | number | - | Maximum width (px) |
fullSize | boolean | true | Take full canvas width/height |
rtl | boolean | - | Right-to-left rendering |
onClick | function | - | Click handler |
onHover | function | - | Hover handler |
onLeave | function | - | Mouse leave handler |
labels: {
boxWidth: 40,
boxHeight: 12,
color: '#666',
font: { size: 12 },
padding: 10,
usePointStyle: false,
pointStyle: 'circle',
filter: (item, data) => item.text !== 'Hidden', // Filter items
sort: (a, b, data) => a.text.localeCompare(b.text) // Sort items
}
plugins: { legend: { display: false } }
For custom click handlers and Legend Item Interface, see references/legend-customization.md.
Namespace: options.plugins.tooltip
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Enable on-canvas tooltips |
external | function | null | External (HTML) tooltip handler |
mode | string | interaction.mode | point, index, dataset, nearest |
intersect | boolean | interaction.intersect | Require intersection |
position | string | 'average' | average, nearest, or custom |
backgroundColor | Color | 'rgba(0,0,0,0.8)' | Background color |
padding | number | 6 | Padding inside tooltip |
cornerRadius | number | 6 | Border radius |
displayColors | boolean | true | Show color boxes |
callbacks: {
title: (items) => items[0].label,
label: (context) => `${context.dataset.label}: ${context.parsed.y}`,
footer: (items) => `Total: ${items.reduce((a, b) => a + b.parsed.y, 0)}`
}
Additional callbacks: beforeTitle, afterTitle, beforeBody, afterBody, beforeLabel, afterLabel, labelColor, labelTextColor, labelPointStyle, beforeFooter, afterFooter.
plugins: { tooltip: { enabled: false } }
For external HTML tooltips, custom positioners, and the full Tooltip Model, see references/tooltip-customization.md and examples/custom-tooltip.html.
Namespace: options.plugins.title
plugins: {
title: {
display: true,
text: 'Chart Title',
color: '#666',
font: { size: 16, weight: 'bold' },
padding: { top: 10, bottom: 10 },
align: 'center', // start, center, end
position: 'top', // top, bottom, left, right
fullSize: true // Take full canvas width
},
subtitle: {
display: true,
text: 'Chart Subtitle',
color: '#999',
font: { size: 12 }
}
}
Chart.js animation has three configuration levels:
| Key | Namespace | Purpose |
|---|---|---|
animation | options.animation | Base animation settings |
animations | options.animations | Per-property animations |
transitions | options.transitions | Mode-specific animations |
animation: {
duration: 1000,
easing: 'easeOutQuart',
delay: 0,
loop: false,
onProgress: (animation) => { /* during animation */ },
onComplete: (animation) => { /* when complete */ }
}
animations: {
tension: {
duration: 1000,
easing: 'linear',
from: 1,
to: 0,
loop: true
},
colors: {
type: 'color',
duration: 500,
from: 'transparent'
}
}
Control animations for specific modes (active, hide, show, reset, resize):
transitions: {
active: { animation: { duration: 400 } },
resize: { animation: { duration: 0 } },
show: {
animations: {
colors: { from: 'transparent' },
visible: { type: 'boolean', duration: 0 }
}
}
}
animation: false // Disable all
// Or per-mode:
transitions: { active: { animation: { duration: 0 } } }
linear, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInSine, easeOutSine, easeInOutSine, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, easeInElastic, easeOutElastic, easeInOutElastic, easeInBack, easeOutBack, easeInOutBack, easeInBounce, easeOutBounce, easeInOutBounce
For animation callbacks and advanced patterns, see references/advanced-animations.md.
Namespace: options.interaction
| Option | Type | Default | Description |
|---|---|---|---|
mode | string | 'nearest' | How to find elements |
intersect | boolean | true | Must intersect element |
axis | string | 'x' | x, y, xy, or r |
includeInvisible | boolean | false | Include hidden elements |
| Mode | Description |
|---|---|
'point' | Elements at same position |
'index' | Elements at same index |
'dataset' | Elements in same dataset |
'nearest' | Nearest element |
'x' | Elements at same x-axis value |
'y' | Elements at same y-axis value |
Namespace: options
| Option | Type | Default | Description |
|---|---|---|---|
events | string[] | ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'] | Browser events to listen for |
onClick | function | null | Click handler over chart area |
onHover | function | null | Hover handler over chart area |
options: {
events: ['click'], // Only respond to clicks
onClick: (event, elements, chart) => {
if (elements.length > 0) {
const { datasetIndex, index } = elements[0];
console.log(chart.data.datasets[datasetIndex].data[index]);
}
},
onHover: (event, elements, chart) => {
chart.canvas.style.cursor = elements.length ? 'pointer' : 'default';
}
}
onClick: (e) => {
const position = Chart.helpers.getRelativePosition(e, chart);
const dataX = chart.scales.x.getValueForPixel(position.x);
const dataY = chart.scales.y.getValueForPixel(position.y);
}
Namespace: options.layout
layout: {
padding: { top: 20, right: 20, bottom: 20, left: 20 },
autoPadding: true // Auto-adjust for labels
}
Global defaults:
Chart.defaults.font.family = "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif";
Chart.defaults.font.size = 12;
Chart.defaults.font.weight = 'normal';
Chart.defaults.font.lineHeight = 1.2;
Chart.defaults.color = '#666';
Per-element font:
font: { family: 'Arial', size: 18, weight: 'bold', style: 'italic', lineHeight: 1.2 }
Supported formats: named ('red'), hex ('#ff0000'), RGB ('rgb(255,0,0)'), RGBA ('rgba(255,0,0,0.5)'), HSL ('hsl(0,100%,50%)'), HSLA.
Global color defaults:
Chart.defaults.backgroundColor = 'rgba(0, 0, 0, 0.1)';
Chart.defaults.borderColor = 'rgba(0, 0, 0, 0.1)';
Chart.defaults.color = '#666';
Default styles for chart elements:
// Points (line, radar, scatter)
Chart.defaults.elements.point.radius = 3;
Chart.defaults.elements.point.hoverRadius = 4;
// Lines
Chart.defaults.elements.line.tension = 0;
Chart.defaults.elements.line.borderWidth = 3;
// Bars
Chart.defaults.elements.bar.borderWidth = 0;
Chart.defaults.elements.bar.borderRadius = 0;
// Arcs (pie, doughnut, polar)
Chart.defaults.elements.arc.borderWidth = 2;
Chart.defaults.responsive = true;
Chart.defaults.maintainAspectRatio = true;
Chart.defaults.interaction.mode = 'nearest';
Chart.defaults.plugins.legend.position = 'bottom';
Chart.defaults.datasets.line.tension = 0.4;
Other configuration topics not covered in detail here:
options.plugins.decimation)options.locale)options.devicePixelRatio)references/advanced-animations.md - Transitions, callbacks, animation objectreferences/tooltip-customization.md - External tooltips, Tooltip Model, custom positionersreferences/legend-customization.md - Legend Item Interface, custom handlersexamples/responsive-chart.html - Proper container setup, flexbox, print handlingexamples/custom-tooltip.html - External HTML tooltip implementationexamples/interactive-legend.html - Custom legend click behavior