Get the FREE Ultimate OpenClaw Setup Guide →

chartjs-tooltips

npx machina-cli add skill sjnims/chartjs-expert/chartjs-tooltips --openclaw
Files (1)
SKILL.md
12.6 KB

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

OptionTypeDefaultDescription
enabledbooleantrueEnable/disable canvas tooltips
externalfunctionnullExternal tooltip handler function
modestring'nearest'Interaction mode (point, nearest, index, dataset)
intersectbooleantrueRequire mouse directly over element
positionstring'average'Tooltip position (average, nearest, or custom)
backgroundColorColor'rgba(0,0,0,0.8)'Background color
titleColorColor'#fff'Title text color
bodyColorColor'#fff'Body text color
borderColorColor'rgba(0,0,0,0)'Border color
borderWidthnumber0Border width
cornerRadiusnumber6Radius of tooltip corner curves
caretSizenumber5Size of tooltip arrow in pixels
caretPaddingnumber2Distance from arrow to tooltip point
displayColorsbooleantrueShow color boxes in tooltip
boxWidthnumberbodyFont.sizeWidth of color box
boxHeightnumberbodyFont.sizeHeight of color box
boxPaddingnumber1Padding between color box and text
usePointStylebooleanfalseUse point style instead of color box
xAlignstringundefinedTooltip caret X position (left, center, right)
yAlignstringundefinedTooltip caret Y position (top, center, bottom)
itemSortfunctionundefinedSort tooltip items callback
filterfunctionundefinedFilter tooltip items callback
rtlbooleanundefinedRender tooltip right-to-left
textDirectionstringcanvas defaultForce 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

CallbackParametersReturnsDescription
beforeTitleTooltipItem[]string|string[]Text before title
titleTooltipItem[]string|string[]Tooltip title
afterTitleTooltipItem[]string|string[]Text after title
beforeBodyTooltipItem[]string|string[]Text before body section
beforeLabelTooltipItemstring|string[]Text before individual label
labelTooltipItemstring|string[]Individual item label
afterLabelTooltipItemstring|string[]Text after individual label
afterBodyTooltipItem[]string|string[]Text after body section
beforeFooterTooltipItem[]string|string[]Text before footer
footerTooltipItem[]string|string[]Tooltip footer
afterFooterTooltipItem[]string|string[]Text after footer
labelColorTooltipItemobjectColor box styling
labelTextColorTooltipItemColorLabel text color
labelPointStyleTooltipItemobjectPoint 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.

ModeBehavior
pointOnly element directly under cursor
nearestNearest element to cursor
indexAll elements at same index
datasetAll elements in dataset
xAll elements with same X value
yAll 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 handlers
  • references/callback-signatures.md - Full callback reference with per-dataset overrides

Examples

  • examples/html-tooltip.html - Complete HTML tooltip implementation
  • examples/conditional-tooltips.html - Filter, sort, and conditional styling examples

Source

git clone https://github.com/sjnims/chartjs-expert/blob/main/skills/chartjs-tooltips/SKILL.mdView on GitHub

Overview

Chart.js tooltips in v4.5.1 are configured under options.plugins.tooltip. This guide explains how to enable, style, position, and tailor tooltip content using callbacks and external handlers to fit your charts and UI needs.

How This Skill Works

Tooltips are controlled by the tooltip plugin via options.plugins.tooltip. You customize behavior with properties like mode, intersect, and position, and you can supply callbacks to build content. For advanced cases, you can provide an external tooltip handler or customize visuals (colors, borders, and shape).

When to Use It

  • When you need custom tooltip content with callbacks (title, label, etc.)
  • When you want to implement an external tooltip handler
  • When you need an HTML-style or custom tooltip
  • When you need to format or style tooltip visuals (colors, borders, fonts)
  • When you want precise tooltip positioning and alignment (position, xAlign/yAlign)

Quick Start

  1. Step 1: In your chart config, set options.plugins.tooltip and, if needed, options.plugins.tooltip.callbacks for custom content
  2. Step 2: If required, implement options.plugins.tooltip.external for an external tooltip renderer
  3. Step 3: Adjust visuals (backgroundColor, borderColor, borderWidth, cornerRadius, displayColors) and test across charts

Best Practices

  • Enable tooltip with sensible defaults and choose a mode (nearest, index) that matches user interaction
  • Use callbacks (title, label, beforeBody, afterBody) to craft clear, concise content
  • If you need custom rendering, consider an external tooltip function
  • Fine-tune visuals with backgroundColor, borderColor, borderWidth, cornerRadius, and displayColors
  • Control item order and visibility with itemSort, filter, and text direction settings

Example Use Cases

  • Basic tooltip with index mode and non-intersect on a bar chart
  • Tooltip content customized via callbacks for title and label
  • External tooltip handler rendering in a separate DOM element
  • HTML tooltip integration for richer content
  • Styled tooltip with colors, borders, and rounded corners

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers