Chartjs Tooltips
by sjnims
This skill should be used when the user asks "Chart.js tooltips", "Chart.js tooltip callbacks", "custom Chart.js tooltip", "HTML tooltip Chart.js", "Chart.js tooltip formatting", "Chart.js tooltip position", "Chart.js tooltip label", "external tooltip", "Chart.js tooltip styling", or needs help configuring tooltips in Chart.js v4.5.1.
Skill Details
Repository Files
5 files in this skill directory
name: chartjs-tooltips description: This skill should be used when the user asks "Chart.js tooltips", "Chart.js tooltip callbacks", "custom Chart.js tooltip", "HTML tooltip Chart.js", "Chart.js tooltip formatting", "Chart.js tooltip position", "Chart.js tooltip label", "external tooltip", "Chart.js tooltip styling", or needs help configuring tooltips in Chart.js v4.5.1.
Chart.js Tooltips (v4.5.1)
Complete guide to configuring and customizing tooltips in Chart.js.
Tooltip Basics
Tooltips display when users hover over chart elements. Chart.js provides extensive customization options.
Basic Configuration
Namespace: options.plugins.tooltip
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true | Enable/disable canvas tooltips |
external |
function | null | External tooltip handler function |
mode |
string | 'nearest' | Interaction mode (point, nearest, index, dataset) |
intersect |
boolean | true | Require mouse directly over element |
position |
string | 'average' | Tooltip position (average, nearest, or custom) |
backgroundColor |
Color | 'rgba(0,0,0,0.8)' | Background color |
titleColor |
Color | '#fff' | Title text color |
bodyColor |
Color | '#fff' | Body text color |
borderColor |
Color | 'rgba(0,0,0,0)' | Border color |
borderWidth |
number | 0 | Border width |
cornerRadius |
number | 6 | Radius of tooltip corner curves |
caretSize |
number | 5 | Size of tooltip arrow in pixels |
caretPadding |
number | 2 | Distance from arrow to tooltip point |
displayColors |
boolean | true | Show color boxes in tooltip |
boxWidth |
number | bodyFont.size | Width of color box |
boxHeight |
number | bodyFont.size | Height of color box |
boxPadding |
number | 1 | Padding between color box and text |
usePointStyle |
boolean | false | Use point style instead of color box |
xAlign |
string | undefined | Tooltip caret X position (left, center, right) |
yAlign |
string | undefined | Tooltip caret Y position (top, center, bottom) |
itemSort |
function | undefined | Sort tooltip items callback |
filter |
function | undefined | Filter tooltip items callback |
rtl |
boolean | undefined | Render tooltip right-to-left |
textDirection |
string | canvas default | Force text direction ('rtl' or 'ltr') |
Basic Example
const chart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
plugins: {
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
backgroundColor: 'rgba(0, 0, 0, 0.9)',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: '#666',
borderWidth: 1
}
}
}
});
Tooltip Callbacks
Customize tooltip content using callbacks.
Namespace: options.plugins.tooltip.callbacks
| Callback | Parameters | Returns | Description |
|---|---|---|---|
beforeTitle |
TooltipItem[] | string|string[] | Text before title |
title |
TooltipItem[] | string|string[] | Tooltip title |
afterTitle |
TooltipItem[] | string|string[] | Text after title |
beforeBody |
TooltipItem[] | string|string[] | Text before body section |
beforeLabel |
TooltipItem | string|string[] | Text before individual label |
label |
TooltipItem | string|string[] | Individual item label |
afterLabel |
TooltipItem | string|string[] | Text after individual label |
afterBody |
TooltipItem[] | string|string[] | Text after body section |
beforeFooter |
TooltipItem[] | string|string[] | Text before footer |
footer |
TooltipItem[] | string|string[] | Tooltip footer |
afterFooter |
TooltipItem[] | string|string[] | Text after footer |
labelColor |
TooltipItem | object | Color box styling |
labelTextColor |
TooltipItem | Color | Label text color |
labelPointStyle |
TooltipItem | object | Point style when usePointStyle is true |
Per-dataset callbacks (beforeLabel, label, afterLabel, labelColor, labelTextColor, labelPointStyle) can be overridden in data.datasets[].tooltip.callbacks.
Format Label with Currency
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(context.parsed.y);
}
return label;
}
}
}
}
}
Add Percentage to Tooltip
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
const dataset = context.dataset;
const total = dataset.data.reduce((sum, val) => sum + val, 0);
const value = context.parsed;
const percentage = ((value / total) * 100).toFixed(2);
return `${context.label}: ${value} (${percentage}%)`;
}
}
}
}
}
Multi-Line Labels
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
return [
`Sales: $${context.parsed.y}`,
`Date: ${context.label}`,
`Region: North America`
];
}
}
}
}
}
Custom Title
options: {
plugins: {
tooltip: {
callbacks: {
title: function(tooltipItems) {
const item = tooltipItems[0];
return `Week of ${item.label}`;
}
}
}
}
}
Custom Footer
options: {
plugins: {
tooltip: {
callbacks: {
footer: function(tooltipItems) {
let sum = 0;
tooltipItems.forEach(item => {
sum += item.parsed.y;
});
return 'Total: ' + sum;
}
}
}
}
}
Interaction Modes
Control which elements trigger tooltips.
| Mode | Behavior |
|---|---|
point |
Only element directly under cursor |
nearest |
Nearest element to cursor |
index |
All elements at same index |
dataset |
All elements in dataset |
x |
All elements with same X value |
y |
All elements with same Y value |
Index Mode (Vertical Line)
options: {
plugins: {
tooltip: {
mode: 'index',
intersect: false // Show even if not directly over point
}
},
interaction: {
mode: 'index',
intersect: false
}
}
Single Point Mode
options: {
plugins: {
tooltip: {
mode: 'point',
intersect: true // Require hover directly over point
}
}
}
HTML Tooltips (External)
Create fully custom HTML tooltips.
Basic HTML Tooltip
const getOrCreateTooltip = (chart) => {
let tooltipEl = chart.canvas.parentNode.querySelector('div.chartjs-tooltip');
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.classList.add('chartjs-tooltip');
tooltipEl.style.background = 'rgba(0, 0, 0, 0.7)';
tooltipEl.style.borderRadius = '3px';
tooltipEl.style.color = 'white';
tooltipEl.style.opacity = 1;
tooltipEl.style.pointerEvents = 'none';
tooltipEl.style.position = 'absolute';
tooltipEl.style.transform = 'translate(-50%, 0)';
tooltipEl.style.transition = 'all .1s ease';
const table = document.createElement('table');
table.style.margin = '0px';
tooltipEl.appendChild(table);
chart.canvas.parentNode.appendChild(tooltipEl);
}
return tooltipEl;
};
const externalTooltipHandler = (context) => {
const {chart, tooltip} = context;
const tooltipEl = getOrCreateTooltip(chart);
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set Text
if (tooltip.body) {
const titleLines = tooltip.title || [];
const bodyLines = tooltip.body.map(b => b.lines);
const tableHead = document.createElement('thead');
titleLines.forEach(title => {
const tr = document.createElement('tr');
tr.style.borderWidth = 0;
const th = document.createElement('th');
th.style.borderWidth = 0;
const text = document.createTextNode(title);
th.appendChild(text);
tr.appendChild(th);
tableHead.appendChild(tr);
});
const tableBody = document.createElement('tbody');
bodyLines.forEach((body, i) => {
const colors = tooltip.labelColors[i];
const span = document.createElement('span');
span.style.background = colors.backgroundColor;
span.style.borderColor = colors.borderColor;
span.style.borderWidth = '2px';
span.style.marginRight = '10px';
span.style.height = '10px';
span.style.width = '10px';
span.style.display = 'inline-block';
const tr = document.createElement('tr');
tr.style.backgroundColor = 'inherit';
tr.style.borderWidth = 0;
const td = document.createElement('td');
td.style.borderWidth = 0;
const text = document.createTextNode(body);
td.appendChild(span);
td.appendChild(text);
tr.appendChild(td);
tableBody.appendChild(tr);
});
const tableRoot = tooltipEl.querySelector('table');
while (tableRoot.firstChild) {
tableRoot.firstChild.remove();
}
tableRoot.appendChild(tableHead);
tableRoot.appendChild(tableBody);
}
const {offsetLeft: positionX, offsetTop: positionY} = chart.canvas;
// Display, position, and set styles
tooltipEl.style.opacity = 1;
tooltipEl.style.left = positionX + tooltip.caretX + 'px';
tooltipEl.style.top = positionY + tooltip.caretY + 'px';
tooltipEl.style.font = tooltip.options.bodyFont.string;
tooltipEl.style.padding = tooltip.options.padding + 'px';
};
// Use external tooltip
const chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
plugins: {
tooltip: {
enabled: false, // Disable canvas tooltip
external: externalTooltipHandler
}
}
}
});
Tooltip Styling
Custom Colors
options: {
plugins: {
tooltip: {
backgroundColor: 'rgba(255, 99, 132, 0.9)',
titleColor: '#fff',
bodyColor: '#fff',
borderColor: 'rgb(255, 99, 132)',
borderWidth: 2,
cornerRadius: 10,
displayColors: true,
padding: 15
}
}
}
Custom Fonts
options: {
plugins: {
tooltip: {
titleFont: {
size: 16,
weight: 'bold',
family: 'Arial'
},
bodyFont: {
size: 14,
weight: 'normal',
family: 'Arial'
}
}
}
}
Disabling Tooltips
// Disable all tooltips
options: {
plugins: {
tooltip: {
enabled: false
}
}
}
// Disable for specific dataset
datasets: [{
label: 'Sales',
data: [10, 20, 30],
tooltip: {
enabled: false
}
}]
Custom Position Modes
Define custom tooltip positioning by adding to Chart.Tooltip.positioners.
import { Tooltip } from 'chart.js';
// Register custom positioner
Tooltip.positioners.topLeft = function(elements, eventPosition) {
const tooltip = this;
return {
x: 0,
y: 0,
xAlign: 'left',
yAlign: 'top'
};
};
// Use custom position
new Chart(ctx, {
type: 'bar',
data: data,
options: {
plugins: {
tooltip: {
position: 'topLeft'
}
}
}
});
TypeScript Declaration
declare module 'chart.js' {
interface TooltipPositionerMap {
topLeft: TooltipPositionerFunction<ChartType>;
}
}
Framework Integration
React
import { Bar } from 'react-chartjs-2';
function ChartWithTooltip() {
const options = {
plugins: {
tooltip: {
callbacks: {
label: (context) => {
return `$${context.parsed.y.toLocaleString()}`;
}
}
}
}
};
return <Bar data={data} options={options} />;
}
Vue
<script setup>
import { Bar } from 'vue-chartjs';
const chartOptions = {
plugins: {
tooltip: {
callbacks: {
label: (context) => {
return `€${context.parsed.y}`;
}
}
}
}
};
</script>
<template>
<Bar :data="chartData" :options="chartOptions" />
</template>
Additional Resources
References
references/tooltip-model.md- Complete tooltip model interface for external handlersreferences/callback-signatures.md- Full callback reference with per-dataset overrides
Examples
examples/html-tooltip.html- Complete HTML tooltip implementationexamples/conditional-tooltips.html- Filter, sort, and conditional styling examples
Related Skills
Team Composition Analysis
This skill should be used when the user asks to "plan team structure", "determine hiring needs", "design org chart", "calculate compensation", "plan equity allocation", or requests organizational design and headcount planning for a startup.
Startup Financial Modeling
This skill should be used when the user asks to "create financial projections", "build a financial model", "forecast revenue", "calculate burn rate", "estimate runway", "model cash flow", or requests 3-5 year financial planning for a startup.
Dbt Transformation Patterns
Master dbt (data build tool) for analytics engineering with model organization, testing, documentation, and incremental strategies. Use when building data transformations, creating data models, or implementing analytics engineering best practices.
Startup Metrics Framework
This skill should be used when the user asks about "key startup metrics", "SaaS metrics", "CAC and LTV", "unit economics", "burn multiple", "rule of 40", "marketplace metrics", or requests guidance on tracking and optimizing business performance metrics.
Market Sizing Analysis
This skill should be used when the user asks to "calculate TAM", "determine SAM", "estimate SOM", "size the market", "calculate market opportunity", "what's the total addressable market", or requests market sizing analysis for a startup or business opportunity.
Anndata
This skill should be used when working with annotated data matrices in Python, particularly for single-cell genomics analysis, managing experimental measurements with metadata, or handling large-scale biological datasets. Use when tasks involve AnnData objects, h5ad files, single-cell RNA-seq data, or integration with scanpy/scverse tools.
Xlsx
Spreadsheet toolkit (.xlsx/.csv). Create/edit with formulas/formatting, analyze data, visualization, recalculate formulas, for spreadsheet processing and analysis.
Geopandas
Python library for working with geospatial vector data including shapefiles, GeoJSON, and GeoPackage files. Use when working with geographic data for spatial analysis, geometric operations, coordinate transformations, spatial joins, overlay operations, choropleth mapping, or any task involving reading/writing/analyzing vector geographic data. Supports PostGIS databases, interactive maps, and integration with matplotlib/folium/cartopy. Use for tasks like buffer analysis, spatial joins between dat
Tensorboard
Visualize training metrics, debug models with histograms, compare experiments, visualize model graphs, and profile performance with TensorBoard - Google's ML visualization toolkit
Deeptools
NGS analysis toolkit. BAM to bigWig conversion, QC (correlation, PCA, fingerprints), heatmaps/profiles (TSS, peaks), for ChIP-seq, RNA-seq, ATAC-seq visualization.
