Home/ Cookbook/ Charts/ Horizontal bars

Rank long-named categories with a horizontal bar chart

By the end of this recipe you'll have a sorted horizontal bar chart with labels alongside each bar — perfect for product names, supplier names, branch names, or anything else too long to fit under a vertical column.

Charts Intermediate ~8 min React · @corelithzw/react

Overview

Bars run left-to-right. Category labels read naturally; the eye scans top-down looking for the longest bar.

Horizontal bars are vertical bars rotated by ninety degrees, and that one rotation is enough to make a different chart useful. Long category names that would have rotated 45° under a column now sit clean. Top-N "leaderboard" reads come free, because sort-by-value descends visually down the page.

Skip horizontal if your x-axis is time (lines and vertical bars own time), or if you've got more than ~15 categories — the page becomes a phone-book and the small differences disappear. For 5–10 ranked items with long names, horizontal is the right shape.

Default opinion: always sort descending. A horizontal bar chart that isn't sorted is just rotated bars — you've thrown away the format's main superpower.

The chart

Top five suppliers by month-to-date spend. Sorted desc; top supplier highlighted.

Top suppliers by spend, month-to-date Five bars: Mukamba Holdings at $48k, Chivhu Logistics at $36k, Harare Steel at $28k, Bulawayo Cables at $19k, Mutare Packaging at $11k. Mukamba Holdings Chivhu Logistics Harare Steel Bulawayo Cables Mutare Packaging $48k $36k $28k $19k $11k $0 $15k $30k $45k
Top supplier Rest
Mukamba Holdings leads at $48k, a third of total spend. Bottom three combined ($58k) outpace the top one.

Required pieces

From @corelithzw/react.

Intended exports used here: Chart.Bar with orientation="horizontal".

Roadmap. Horizontal orientation ships with Chart.Bar in @corelithzw/react v0.2.

The React snippet

Same component as vertical bars; flip orientation and sort the data on the way in.

TopSuppliers.tsx@corelithzw/react

Customising

Three forks.

Tint the top three

Highlight a podium — gold, silver, bronze — so the top tier reads as a group, not just a winner.

color={(d, i) =>
  i === 0 ? 'brand' :
  i === 1 ? 'brand-300' :
  i === 2 ? 'brand-100' :
  'brand-soft'}

Trim the tail

Cap at top-5 plus an "Other" row containing the long tail. Keeps the chart honest without 30 unreadable bars.

const [top, rest] = [
  data.slice(0, 5),
  data.slice(5),
];
const folded = [...top, {
  supplier: 'Other',
  spend: rest.reduce((s, d) => s + d.spend, 0),
}];

Slide-in from left

Animate from width: 0 on first paint. The eye reads the order as it draws.

<Chart.Bar
  data={data}
  orientation="horizontal"
  animate="grow"
  animateStaggerMs={50}
  height={280}
/>

In context

Inside a row card on mobile — supplier name + spend + bar, all on one row.

Top suppliers
MTD · $142k
Mukamba Holdings$48k Chivhu Logistics$36k Harare Steel$28k Bulawayo Cables$19k Mutare Packaging$11k

Accessibility

Horizontal bars carry their labels in the chart, which means the screen-reader has more to work with — use it.

  • Role and label. Root <svg> uses role="img" + aria-labelledby on inline <title> + <desc>.
  • Each row is a group. Wrap each bar + label pair in <g aria-label="Mukamba Holdings: $48,000">. Tabbing reads the chart like a leaderboard.
  • Sort is part of the message. Note the sort order in the <desc> ("sorted descending by spend") so the order itself is announced.
  • SR summary. A .ck-sr-only paragraph names the leader, the gap to second, and the long-tail share.
  • Keyboard. Each bar is tabindex="0"; Arrow keys walk top-to-bottom.