DotPlot
React dot plot chart — values as dots on a shared scale for precise comparison. Tiny accessible SVG microchart; RSC-safe static or /interactive.
DotPlot answers "how do a few named values compare on one scale?" with the minimum ink per comparison. Dots over bars when the scale doesn't start at zero — position lies less than truncated bar length.
Install
import { DotPlot } from "@microcharts/react/dot-plot";// team — real values under “Sample data” below<DotPlot data={team} title="Review scores" />Sample data
const team = [ { label: "Ada", value: 96 }, { label: "Kim", value: 41 }, { label: "Sam", value: 88 }, { label: "Noor", value: 73 }, { label: "Lee", value: 60 },];Try it
When to use it
- Good for — KPI leaderboards, named comparisons in cards, rows where a truncated bar would lie.
- Avoid for — more than 7 rows or time series (Sparkline).
Sizing
Variants
Edge cases
An empty series has nothing to compare, so no dots draw and the accessible name reads "No data." A single category
still renders normally — one dot, one label — with the summary's "category"/"categories" wording matching the count
("1 category. Highest Only 42, lowest Only 42."). A null value draws no dot and no label for its row, but the row
still occupies its slot in the vertical rhythm — the real values around it keep the same spacing they'd have in a fully
populated set — and it's excluded from the category count in the summary, not counted as a comparison with nothing.
Four homes
Why this default
Without stem the domain fits the data (a position read); with stem the domain is forced through zero (a magnitude
read) — the prop flips the honesty regime, and the docs say so. Coincident dots on adjacent rows de-overlap by half a
unit; labels truncate by character count and drop entirely when rows get too dense — all pure arithmetic, nothing
measured.
Accessibility
The accessible name carries count and extremes — "3 categories. Highest Ada 96, lowest Kim 41." The interactive entry roves rows and announces each with its rank ("Ada: 96 — 1st of 3.").
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 }[] | Named values. |
| stem | boolean | Hairline from zero — flips to a magnitude read (zero-anchored domain forced). |
| highlight | number | string | Accent one category. |
| label | "value" | "none" | Value text beside each dot (drops out under 8-unit rows). |
| 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.
Related charts
HeatStrip
React heat strip chart — ordered intensity along a single strip for dense series. Tiny accessible SVG microchart; RSC-safe static or /interactive.
Dumbbell
React dumbbell chart — before/after or A/B pairs as dots linked on one scale. Tiny accessible SVG microchart; RSC-safe static or /interactive.