Skip to content
microcharts
ReferenceDecisionQuadrantDot

QuadrantDot

React quadrant dot chart — a focal 2-D point against peers on a split cross. Tiny accessible SVG microchart; RSC-safe static or /interactive.

QuadrantDot answers "where does this item sit in the 2×2 — against the field?". A focal dot is placed by 2-D position, a hairline cross marks the split (the domain midpoints by default, always overridable but never hidden), and the peers show as tiny muted ghosts. The read is quadrant membership first; exact position is the second read — which is why it lives at glyph scale.

QuadrantDot
interactive · 4.83 kB · static · 2.42 kB

Install

Import & usereact/quadrant-dot
import { QuadrantDot } from "@microcharts/react/quadrant-dot";// item, backlog — real values under “Sample data” below<QuadrantDot data={item} field={backlog} xLabel="effort" yLabel="impact" title="Effort vs impact" />
Sample data
// a prioritization backlog — effort (x) vs impact (y)const item = { x: 3, y: 9 };const backlog = [  { x: 2, y: 8 },  { x: 8, y: 9 },  { x: 3, y: 7 },  { x: 9, y: 2 },  { x: 7, y: 3 },  { x: 1, y: 1 },  { x: 5, y: 6 },  { x: 6, y: 8 },  { x: 4, y: 3 },  { x: 8, y: 5 },  { x: 2, y: 4 },  { x: 7, y: 7 },  { x: 3, y: 2 },  { x: 6, y: 1 },];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — the classic prioritization 2×2 (one cell per initiative in a table), an effort-vs-impact read in a KPI card, any "which quadrant, against the field" decision.
  • Avoid for — a full scatter plot (MicroScatter) or a single ranked list (MiniBar).

Sizing

Variants

lone glyph + named quadrants

Edge cases

degenerate axis — split line hidden on that axis only
a peer coincident with the focal
non-finite focal

When every field value on one axis equals the focal's, that axis's domain collapses to a point — the split line on that axis is dropped rather than drawn at an arbitrary spot, while the other axis's split still renders. A peer exactly on top of the focal is still counted (distance 0) and sorts first in the interactive entry's nearest-first order. A non-finite focal position draws no marks at all — no cross, no tint, no peers — and carries the "No data." summary, the same degenerate path an empty series takes elsewhere in the library.

Four homes

Why this default

24×24, because the 2×2 is a position read, not a scatter plot — you want to know the quadrant at a glance, and the exact coordinates only when you look closer. The split is data, not decoration: it renders wherever the split truly is and is always overridable, never invisible. With the axes unlabeled at glyph size, the title and summary are load-bearing — skipping them is the one named anti-pattern for this chart, so always pass xLabel, yLabel, and a title.

Accessibility

The accessible name states the focal position and the axis-relative quadrant — "Impact 9, effort 3 — in the high-impact, low-effort quadrant." — adding how crowded that quadrant is when a field is given, or your own words via quadrants={["quick win", …]}. The interactive entry starts on the focal, then cycles peers nearest-first — each announced with its coordinates and quadrant.

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*{ x; y }The focal item's 2-D position.
field{ x; y }[]The peer set — omit for a lone glyph.
xDomain[number, number]The x-axis range (default: derived from the data); domain stays the y-axis.
domain[number, number]The y-axis range (default: derived from the data).
split[number, number]The quadrant boundary (default domain midpoints) — never hidden.
quadrants[TL, TR, BL, BR]Names in reading order — summaries only, never rendered.
xLabel / yLabelstringAxis nouns for the summary — pass them, the axes are unlabeled at glyph size.
regionbooleanFaint tint on the focal's quadrant (default true; false for dense grids).
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