BalanceBeam
A beam that tilts toward the heavier of two sides, with area-true weights and a tilt that saturates.
- encodes
- beam tilt direction + saturating angle
- precision
- medium
- nodes
- ≤ 6
BalanceBeam takes two values and tilts a beam toward the heavier one, so which side wins reads instantly. Inflow is 620,
outflow is 480, and the beam tilts toward inflow. The angle grows with the imbalance, but it saturates at maxTilt
degrees: past that point a steeper beam would imply a precision the eye can't extract, so read the tilt as direction
plus rough magnitude. The two weights are area-true — their area, not their width, is proportional to value. For a
precise comparison, use PairedBars or Delta.
Install
import { BalanceBeam } from "@microcharts/react/balance-beam";<BalanceBeam data={[{ label: "Inflow", value: 620 }, { label: "Outflow", value: 480 }]} />Try it
When to use it
Use it 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 point. For exact ratios use PairedBars or Delta, for more than two items MiniBar, and for trends a time-series chart.
Sizing
Variants
mode="ratio" is the default, because most two-sided comparisons are share-of-whole questions. mode="difference"
scales the imbalance by a shared domain, so rows on the same scale tilt comparably. Square weights are the default
because circles under-read area at this size; shape="round" swaps them.
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 zero area.
Four homes
Accessibility
The accessible name states both sides and the winner — "Inflow 620 vs Outflow 480; Inflow heavier." — or "…; balanced." when they match. The two channels always agree: the tilt direction and the larger weight area point at the same side. 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. |
| fontSize | number | Type size of the weight numerals, in viewBox units. Defaults from `height`. |
| 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.