BalanceBeam
React balance beam chart — which of two sides outweighs, with area-true weights. Tiny accessible SVG microchart; RSC-safe static or /interactive.
BalanceBeam answers "which of two sides outweighs, and roughly by how much?" A beam tilts toward the heavier side; the
direction is instant and the angle grows with the imbalance, but it saturates — read it as direction plus rough
magnitude, not an exact ratio. The two weights are area-true (their area, not their width, is proportional to value).
For a precise comparison, reach for PairedBars or Delta; this is for the glance.
Install
import { BalanceBeam } from "@microcharts/react/balance-beam";<BalanceBeam data={[{ label: "Inflow", value: 620 }, { label: "Outflow", value: 480 }]} />Try it
When to use it
- Good for — a buy vs sell or in vs out read in a sentence, a pro vs con weight in a KPI card, or an A-vs-B pair where direction is the story.
- Avoid for — exact ratios (PairedBars / Delta), more than two items (MiniBar), or trends.
Sizing
Variants
format also takes Intl.NumberFormatOptions — with a locale, both the announced values and the in-chart numerals
(label="values") follow that locale's own grouping and decimal marks.
Edge cases
Equal values level the beam and report "balanced" rather than picking an arbitrary heavier side. Two zeros are the same case — the beam stays level and both weights shrink to nothing, which is honest: there is nothing to weigh.
Four homes
Why this default
Ratio mode is the default because most two-sided comparisons are share-of-whole questions, and square weights are the
default because circles under-read area at this size. The tilt saturates at maxTilt degrees — a deliberate honesty
choice: past a point, a steeper beam would imply a precision the eye can't extract, so the angle levels off. Direction
and rough magnitude always agree, and the two channels (tilt and weight area) never disagree. For same-scale rows that
should tilt comparably, mode="difference" scales the imbalance by a shared domain.
Accessibility
The accessible name states both sides and the winner — "Inflow 620 vs Outflow 480; Inflow heavier." — or "…; balanced." when they match. The interactive entry eases the beam to its new tilt, reveals a side's value on hover or ←/→, and announces when the heavier side flips.
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},{label,value}] | Exactly two items. |
| maxTilt | number | Degrees at full saturation (default 12). |
| shape | "square" | "round" | Weight shape (default square). |
| mode | "ratio" | "difference" | ratio = share-of-whole; difference = absolute, scaled by domain. |
| 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.
Related charts
Hourglass
React hourglass chart — sand area that splits elapsed and remaining, area-true. Tiny accessible SVG microchart; RSC-safe static or /interactive.
SproutRow
React sprout row chart — growth across items as sprouting marks from a shared baseline. Tiny accessible SVG microchart; RSC-safe static or /interactive.