caliper uidocs

Diverging bar chart

Free

Agree–disagree answers centred on neutral, so questions compare by sentiment. Segments grow outward from the centre line.

Installs components/ui/diverging-bar-chart.tsxDepends on d3-shapeMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/diverging-bar-chart.json
How much do you agree? (Q3 customer survey)
  • The app is fast
  • Pricing is fair
  • Docs answer my questions
  • Support is helpful
How much do you agree? (Q3 customer survey)
QuestionStrongly disagreeDisagreeNeutralAgreeStrongly agree
The app is fast814229670
Pricing is fair2648615223
Docs answer my questions1230448836
Support is helpful49258191

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 #

terminal
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.

example.tsx
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 #

divergingShares

component

No props of its own; it accepts the native props of its root element.

DivergingBarChart

component
PropTypeDefaultDescription
label *string—
scale *readonly string[]—Answer labels from most negative to most positive, e.g. five Likert steps.
rows *readonly DivergingRow[]—
loadingboolean—
errorstring—
classNamestring—

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.