BreathingDot
React breathing dot chart — ambient load as pulse rate, with a static reduced-motion twin. Tiny accessible SVG microchart; RSC-safe static or /interactive.
BreathingDot answers "how loaded is the system right now?" as an ambient signal. In the interactive entry the dot
pulses — slow and small when calm, fast and large when strained — so you feel the state without reading a number.
The static frame is a real chart with zero JavaScript: a core dot colored by band, and a ring whose distance from the
core is the level. This is a low-precision ambient read; for an exact figure reach for Progress or Sparkline.
Install
import { BreathingDot } from "@microcharts/react/breathing-dot";<BreathingDot value={0.42} title="Load" />Try it
Motion, and reduced motion
The pulse is the encoding — its rate and amplitude are snapped to three named bands (calm, elevated, strained), so
the motion is readable, not decorative. This is the deliberate exception to the no-looping-animation rule, allowed only
because the loop parameter (the rate) is the datum. The animation is gated on two things: it pauses when the dot scrolls
off-screen (a shared observer), and it never runs at all under prefers-reduced-motion — reduced-motion readers get
exactly the static frame, where the ring's distance from the core already carries the level. The band is announced
through a polite live region only when it changes, never on every pulse.
When to use it
- Good for — an ambient "how strained is it right now" read, a live status dot in a header or KPI card, or per-node load in a dense table.
- Avoid for — an exact load figure (
Progress,Sparkline), discrete events (HeartbeatBlip), or a trend over time (Sparkline).
Sizing
One size prop, in viewBox units, sets the glyph box — it defaults to 16, about the height of a line of body text.
There is no separate width/height: the dot is square, and the rendered box widens only by the gutter a label
reserves. fontSize follows size unless you set it.
Variants
Edge cases
format/locale reach the label="value" percent numeral — always a whole percent, so a locale mostly changes digit
shapes here, not grouping or decimals. The band words in the accessible summary ("calm" / "elevated" / "strained") stay
in strings (BreathingDotStrings), not the number formatter.
Four homes
Why this default
Three bands, because ambient motion supports about three discriminable states — more would be false precision. The band
color is always doubled: by the ring offset in the static frame and by the pulse rate in motion, so the state never
rests on color alone. When the value is unknown (null or NaN) the dot goes gray, drops its ring, and never
pulses — an unknown system must not look calm. The boundary with HeartbeatBlip: a continuous level is a
BreathingDot; discrete arriving events are a HeartbeatBlip.
Accessibility
The accessible name is the level and its band word — "Load 20% — calm." — or "Load unknown." when the value is
missing. The band color is never the only signal (ring offset and pulse rate double it), motion is fully gated on
prefers-reduced-motion, and the live region announces band changes only.
This chart is a single unit, so there is nothing to rove between: a click, tap, Enter or Space selects it
and fires onSelect, and no selection stays pinned. That is the scalar half of the shared
interaction contract.
Props
| Prop | Type | Notes |
|---|---|---|
| value* | number | Level 0–1 (clamped). null / NaN → unknown. |
| thresholds | [number, number] | calm / elevated / strained edges (default [0.5, 0.8]). |
| label | "value" | "none" | Percent numeral beside the dot. |
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
SpiralYear
React spiral year chart — a full year of values wound as a spiral by day or week. Tiny accessible SVG microchart; RSC-safe static or /interactive.
HeartbeatBlip
React heartbeat blip chart — recent events as blips in a live window. Tiny accessible SVG microchart; RSC-safe static or /interactive.