Horizontal Bars in Chart.js: indexAxis, Not horizontalBar
Chart.js 3.x/4.x uses indexAxis: 'y' for horizontal bars, replacing the removed horizontalBar type. A minimal config, axis implications, migration notes, and a verification path.
20 Dec 2025, 22:16 UTC

Long category names are the classic case where a vertical bar chart falls apart: labels overlap, get truncated, and the chart becomes unreadable. The fix in Chart.js 3.x/4.x is not a chart type but a single option — indexAxis: 'y'. If you are still searching for horizontalBar, that type was removed in v3; indexAxis is its replacement.
indexAxis: the supported way to flip a bar chart
indexAxis tells Chart.js which cartesian axis is the index (category) axis. The default is 'x', which gives you vertical bars. Setting it to 'y' makes the y-axis the category axis, so bars extend horizontally from left to right. This works for Chart.js 3.x and 4.x — it is not a v4-only feature, and it is the direct answer to the old horizontalBar type from v2.
A minimal working example
const chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Alpha', 'Beta', 'Gamma'],
datasets: [{ label: 'Score', data: [3, 7, 5] }]
},
options: {
indexAxis: 'y',
responsive: true
}
});Swap 'y' to 'x' and call chart.update() and the same instance re-renders vertically — no need to destroy and recreate the chart. You can verify the orientation programmatically by checking chart.options.indexAxis and inspecting chart.scales to see which axis Chart.js treats as the index axis.
What changes when you flip the axis
Orientation is not just cosmetic. Scales, ticks, tooltips, and bar thickness calculations all follow the swapped orientation. If you had custom axis options on scales.x, they now apply to the value axis (horizontal), and scales.y becomes the category axis. Tooltip callbacks that reference parsed.x and parsed.y still work, but the meaning of x and y in callbacks flips accordingly. Stacked bars, time scales, and tick callbacks should be reviewed after switching — don't assume the same options carry over cleanly.
Migrating from horizontalBar
Any v2-era snippet with type: 'horizontalBar' needs to become type: 'bar' plus options.indexAxis: 'y'. The rest of the data structure stays the same. After migrating, verify against the installed version: log Chart.version, then confirm chart.options.indexAxis reads 'y' and that chart.scales.y is the category axis. Mixed-version snippets are a common source of subtle bugs — v2 options like scales.xAxes don't exist in v3+ at all.
Trade-offs and limitations
Horizontal bars solve the long-label problem but not the too-many-categories problem. With dozens of categories the y-axis still crowds; aggregation or filtering is usually better than squeezing more bars in. Also, indexAxis does not fix responsive sizing — the canvas still needs a container with explicit CSS height, otherwise the chart may collapse. Test with a narrow container and long labels to check truncation and tooltip placement before shipping.
Verify before you ship
Check the installed version, render the minimal config, confirm bars extend horizontally, then flip indexAxis to 'x', call update(), and confirm it returns to vertical without recreating the instance. If it does, your version supports the pattern and you can confidently use it for runtime toggles.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.