PairedBars
PairedBars sets a value against its reference, category by category, on one zero-anchored domain.
- encodes
- adjacent bar lengths, zero-anchored
- precision
- high
- nodes
- 2 per pair (pairs ≤ 5)
East came in at 940 against a plan of 1,200, West a little over its own: PairedBars draws each value beside its reference, category by category. Both bars in a pair share one zero-anchored domain, so their lengths are always comparable. The reference is muted by two structural cues, opacity and width, never color alone.
Install
import { PairedBars } from "@microcharts/react/paired-bars";// regions — real values under “Sample data” below<PairedBars data={regions} title="Actual vs plan" />Sample data
const regions = [ { label: "East", value: 940, ref: 1200 }, { label: "West", value: 410, ref: 400 }, { label: "South", value: 620, ref: 600 }, { label: "North", value: 120, ref: 300 },];Try it
When to use it
Use it for budget vs actual per region and target vs result rows. For data without a reference series use MiniBar, and keep it to 5 pairs or fewer.
Sizing
Variants
Grouped is the default because overlapping bars hide small overshoots. Reach for mode="overlay" when the cell is too
tight for two bars per pair.
The gap named in the summary follows format/locale — 12000 reads "12.000" under de-DE rather than the English
"12,000".
Edge cases
A pair whose ref is null draws its value bar alone, with no ghost and no zero-width placeholder, and the interactive
entry announces it as "East: 940, no reference." A chart where every reference is missing dev-warns and points you
to MiniBar. Past 5 pairs the grouped read blurs, so the component still renders every pair and logs a dev warning.
Four homes
Accessibility
The accessible name leads with the largest gap — "2 pairs. Largest gap East: 940 vs 1,200." The interactive entry roves pairs and announces each as value vs reference ("East: 940 vs 1,200.").
The interactive entry follows the shared interaction contract:
arrow keys rove between units on both axes, Home and End jump to the ends, and a click, tap, Enter or
Space selects a unit — pinning its readout so it survives blur, until you select it again or press Escape.
On touch, a tap pins and a drag scrubs.
Props
| Prop | Type | Notes |
|---|---|---|
| data* | { label; value; ref }[] | Value + reference per category. |
| mode | "grouped" | "overlay" | Overlay puts the ref as a full-width ghost behind — halves the footprint. |
| positive | "up" | "down" | Over/under-reference valence tint. |
| orientation | "horizontal" | "vertical" | Rows for wide cells. |
| locale | string | string[] | BCP 47 locale(s) for the gap named in the summary, e.g. "de-DE". |
| animate | boolean | interactiveOpt-in entrance motion when the chart mounts client-side — add import "@microcharts/react/motion" once. Inert on the server, on hydrated server HTML, and under prefers-reduced-motion. |
Plus the shared grammar — data, domain, color, title, summary, format — and the layout props (width, height, className, style) that every chart accepts. Interactive entries also share animate and live, and — wherever a chart has more than one navigable unit — onActive, onSelect, selectedIndex and defaultSelectedIndex; and — wherever the chart shows a hover value — readout. See the shared grammar.