Adding Always‑Visible Data Labels to Chart.js Bar Charts with a Custom Plugin
Learn how to add static data labels to Chart.js bar charts using a custom plugin, improving accessibility and readability with minimal overhead.
04 Nov 2025, 15:51 UTC

Problem: Hiding Exact Values Behind Tooltips
When a bar chart relies only on tooltips to show the numeric value of each bar, users who cannot hover—such as those using screen readers, touch‑only devices, or keyboard navigation—lose access to the precise data. This reduces both accessibility and discoverability, especially in dashboards where quick insight is needed.
Thesis: A lightweight Chart.js plugin can render static labels on every bar, giving always‑visible information without sacrificing the chart’s interactivity.
Solution Overview
Chart.js v4 exposes a plugin API that lets you hook into the drawing lifecycle. By implementing an afterDraw handler we can measure each bar’s geometry and draw the formatted value directly onto the canvas. The plugin runs at render time, so the labels update automatically when the chart is resized or the data changes.
Worked Example: Plugin Implementation
Start with a basic bar chart markup:
Chart.js Bar Chart with Data Labels
The plugin iterates over each bar (meta.data), calculates the label’s x‑position using the category scale and the y‑position just above the bar’s top, then uses Canvas fillText to draw the value. Font size and colour can be adjusted to match your design system.
Trade‑offs and Limitations
- Bundle size: Adding the plugin increases the JavaScript payload by a few hundred bytes when bundled; however, if you already load Chart.js from a CDN the impact is minimal.
- Canvas resizing: The plugin relies on the chart’s current scale values. When the container changes size, Chart.js updates the scales before the next draw, so labels stay aligned. If you manually change the canvas width/height attributes without triggering
chart.update(), labels may appear misplaced. - Label overlap: With very long numeric strings or densely grouped bars, labels can collide. Mitigation strategies include:
- Formatting numbers (e.g.,
value.toLocaleString()or abbreviating thousands as “K”). - Reducing font size or rotating labels (
ctx.rotate) when overlap is detected. - Enabling a collision‑avoidance layout (more complex, outside the scope of this simple plugin).
- Dynamic data updates: To keep plugin bindings intact, call
chart.update()instead of destroying and recreating the chart instance when the dataset changes.
Actionable Closing
If your users need to see exact values without hovering, copy the plugin snippet above, adjust the font and positioning to match your UI, and test the chart at various viewport sizes. Verify that labels remain legible and do not get clipped when the container shrinks. This approach gives you always‑visible data labels while preserving Chart.js’s interactive features.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.