Diverging bar chart
FreeAgree–disagree answers centred on neutral, so questions compare by sentiment. Segments grow outward from the centre line.
pnpm dlx shadcn@latest add https://caliperui.site/r/diverging-bar-chart.json- The app is fast
- Pricing is fair
- Docs answer my questions
- Support is helpful
| Question | Strongly disagree | Disagree | Neutral | Agree | Strongly agree |
|---|---|---|---|---|---|
| The app is fast | 8 | 14 | 22 | 96 | 70 |
| Pricing is fair | 26 | 48 | 61 | 52 | 23 |
| Docs answer my questions | 12 | 30 | 44 | 88 | 36 |
| Support is helpful | 4 | 9 | 25 | 81 | 91 |
When to use #
Use it for
- Survey and NPS-style questions on a five or seven step scale.
- Comparing many questions on the same scale.
Skip it when
- Scales without a neutral middle point that means something.
- A single question; a sentence with the percentages is clearer.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/diverging-bar-chart.json
Adds its 3 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above. It is built from divergingShares and DivergingBarChart.
import { DivergingBarChart } from "@/components/ui/diverging-bar-chart" export function DivergingBarChartDemo() { return ( <DivergingBarChart label="How much do you agree? (Q3 customer survey)" className="w-full" scale={["Strongly disagree", "Disagree", "Neutral", "Agree", "Strongly agree"]} rows={[ { id: "fast", label: "The app is fast", counts: [8, 14, 22, 96, 70] }, { id: "price", label: "Pricing is fair", counts: [26, 48, 61, 52, 23] }, { id: "docs", label: "Docs answer my questions", counts: [12, 30, 44, 88, 36] }, { id: "support", label: "Support is helpful", counts: [4, 9, 25, 81, 91] }, ]} /> ); }
API reference #
DivergingBarChart
component
Accessibility #
It is built on native elements and keeps aria-label, aria-busy and aria-hidden in step with state.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.