Skip to content
microcharts
ReferenceDecisionBenchmarkStrip

BenchmarkStrip

React benchmark strip chart — one value against its cohort's empirical quantiles, with percentile stated. Tiny accessible SVG microchart; RSC-safe static or /interactive.

BenchmarkStrip answers "is this value normal for its peer group?". A focal dot sits on a common scale against the peers' own empirical quantile bands — never a fitted distribution. There is no axis: the band is the reference frame. Small samples fall back to min–max so tail quantiles are never fiction.

BenchmarkStrip
interactive · 5.26 kB · static · 2.97 kB

Install

Import & usereact/benchmark-strip
import { BenchmarkStrip } from "@microcharts/react/benchmark-strip";// peerLatencies — real values under “Sample data” below<BenchmarkStrip data={peerLatencies} value={312} format={{ style: "unit", unit: "millisecond" }} title="Latency vs peers" />
Sample data
// 42 peer latencies (ms)const peerLatencies = [180, 201, 237, 286, 341, 396, 443, 394, 412, 413, 398, 372, 340, 310, 205, 196, 205, 230, 271, 322, 378, 347, 391, 421, 434, 430, 412, 383, 268, 239, 221, 218, 231, 261, 306, 275, 331, 382, 422, 447, 455, 447];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — a value against its cohort, per-row peer comparison in tables, SLA context.
  • Avoid for — a single trend (Sparkline) or two groups head-to-head (ABStrips).

Sizing

Variants

range + label
locale

format also takes Intl.NumberFormatOptions — with a locale, both the right-gutter label and the accessible summary's numbers follow that locale's own grouping and decimal marks: the value above reads "1.240" in German, not "1,240".

Edge cases

n < 8 auto-falls back to min–max
all peers equal
value outside a fixed domain

Four homes

Why this default

Bands come from the peers' own empirical quantiles, never a fitted distribution — the strip never implies a normal curve that the data doesn't back up. There is no axis: the band itself is the reference frame, so the focal dot's position against it is the whole read. Below 8 peers, tail quantiles (p5/p95) are statistically unreliable, so the outer band falls back to the observed min–max automatically — a deliberate honesty trade the range prop can also force at any sample size. A value that falls outside the plotted domain clamps to the edge and draws a small wedge rather than silently disappearing.

Accessibility

The accessible name states the value, its percentile, the peer count, and the middle-half interval — "312 — 43rd percentile of 42 peers (middle half 244.5–408.5)." A flat cohort states it plainly instead: "52 — all 8 peers at 50." The interactive entry roves the five quantile edges with ←/→, announcing each edge's name and value (e.g. "p75: 408.5.").

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*number[]Peer values.
value*numberThe focal reading.
range"p5p95" | "minmax"Outer band; minmax for small samples.
label"value" | "percentile" | "none"What the right gutter states (default percentile).
positive"up" | "down"Which side of the band is good (colors the focal dot).
medianbooleanCenter tick (default true).
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