Skip to content
microcharts
ReferenceExpressiveBalanceBeam

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.

BalanceBeam
interactive · 4.79 kB · static · 2.35 kB

Install

Import & usereact/balance-beam
import { BalanceBeam } from "@microcharts/react/balance-beam";<BalanceBeam data={[{ label: "Inflow", value: 620 }, { label: "Outflow", value: 480 }]} />
Needs package + stylesheetSet up with AI

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

round weights + balanced

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.

locale

Edge cases

balanced — level beam
both zero — level beam, no weights to see

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

PropTypeNotes
data*[{label,value},{label,value}]Exactly two items.
maxTiltnumberDegrees at full saturation (default 12).
shape"square" | "round"Weight shape (default square).
mode"ratio" | "difference"ratio = share-of-whole; difference = absolute, scaled by domain.
animatebooleaninteractiveOpt-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