RateVolume
RateVolume plots a rate line over the volume bars behind it, so a rate is never read without its denominator.
- encodes
- line position (rate) over zero-anchored ghost bars (volume)
- precision
- high for rate, low-deliberate for volume
- nodes
- 1 per bar + ≤ 5
RateVolume draws a precise rate line over low-precision ghost volume bars, which are the denominator. No prop
removes the bars: a 4.1% conversion rate reads very differently on 38 events than on 3,800. The bars are muted and
unlabeled because the question they answer is "enough?", not "how many?". Set minVolume and any period below it
renders its rate point hollow, a shape cue that survives forced-colors and print.
Install
import { RateVolume } from "@microcharts/react/rate-volume";// periods — real values under “Sample data” below<RateVolume data={periods} minVolume={50} title="Conversion rate" />Sample data
const periods = [ { rate: 0.023, volume: 220 }, { rate: 0.025, volume: 190 }, { rate: 0.028, volume: 160 }, { rate: 0.029, volume: 130 }, { rate: 0.031, volume: 110 }, { rate: 0.034, volume: 90 }, { rate: 0.036, volume: 66 }, { rate: 0.041, volume: 38 },];Try it
When to use it
Use it for a conversion or error rate with its denominator, a KPI card where the rate is the headline, and spotting a big rate move on thin volume. When volume itself needs a precise read, pair a SparkBar; for a plain series use Sparkline.
Sizing
Variants
format and volumeFormat both take Intl.NumberFormatOptions and share the same locale. Under de-DE the rate
label reads "4,1 %" and volumes group with a period ("3.800"), following that locale's own conventions rather than a
hardcoded English format.
Edge cases
A period with zero (or non-finite) volume renders no bar and no rate mark. A rate on zero volume is undefined regardless of the input, so the line gaps across that period instead of interpolating through one nothing was measured on, and the interactive entry announces it as "no events" rather than a rate. With no data at all, the chart renders an empty root and the accessible name says "No data."
Four homes
Accessibility
The accessible name always pairs the rate with its volume: "4.1% on 38 events (low volume); up from 2.3% across 5 periods." The interactive entry steps the periods, and its live region states the volume with every rate, announcing "no events" for a zero-volume period.
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* | { rate; volume }[] | Periods, oldest first — each a rate and the volume it was measured on. |
| minVolume | number | Below it, the rate mark renders hollow — 'insufficient denominator'. |
| curve | "linear" | "step" | Step suits per-period aggregate rates. |
| volumeFormat | Intl.NumberFormatOptions | (n) => string | Volume has different units than rate; formatted separately. |
| unit | string | Noun for the volume unit in the summary (default 'events'). |
| volumeDomain | [number, number] | Volume (bar) domain — defaults to [0, max], zero-anchored. |
| label | "last" | "none" | Endpoint rate in a right gutter. |
| 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.