Skip to content
microcharts
ReferenceCoreHorizon

Horizon

React horizon chart — banded horizon encoding for dense magnitude over time. Tiny accessible SVG microchart; RSC-safe static or /interactive.

Horizon answers "what happened across this wide-range series — in a 14-pixel row?" The series is cut into bands and folded: layer opacity carries magnitude, so extremes stay visible at heights where a sparkline would flatten into noise.

How to read it — every band rises from the row's bottom edge, positive or negative; darker means farther from the baseline, not which direction. Above-baseline values shade in the accent color, below-baseline in the negative color, so direction is never color-alone even though both fold upward the same way.

Horizon
interactive · 5.12 kB · static · 2.81 kB

Install

Import & usereact/horizon
import { Horizon } from "@microcharts/react/horizon";// cpuLoad — real values under “Sample data” below<Horizon data={cpuLoad} title="Cluster load" />
Sample data
const cpuLoad = [  2, 5, 9, 14, 22, 31, 26, 18, 12, 24, 38, 45, 41, 30, 19, 11, 6, 3, 8, 16, 27, 35, 29, 20,];
Needs package + stylesheetSet up with AI

Try it

When to use it

  • Good for — dense monitoring rows (dozens stacked), wide-range series in tight cells.
  • Avoid for — first-glance audiences (folding needs a key), or a few rows with room (Sparkline).

Sizing

Variants

three folds
fold around a target
locale

format also takes Intl.NumberFormatOptions — with a locale, the accessible summary's range and last-value numbers follow that locale's own grouping ("4.500" in German, not "4,500"). The interactive readout's per-point values localize the same way; the folded geometry never changes.

Edge cases

negative values — the mirrored read
identical values → a flat block, not empty

Negative values take the negative token and fold from the same bottom edge as positive values (the default mode="mirror") — both directions get darker as they move away from the baseline, so "denser" always means "farther from typical," never "which sign." Identical values across the whole row still render as a solid block rather than vanishing, keeping "flat" visibly distinct from "no data."

Four homes

Why this default

Two folds is the default because it needs no training to read approximately; three folds trade learnability for density and should be reserved for ranges that genuinely span them. The baseline is authored, never inferred — a fold origin is a claim about what "normal" means.

Accessibility

The accessible name reads the unfolded series — "Trending up 900%. Range 2 to 45. Last value 20." — so screen-reader users get the true values, not the folded geometry. The interactive readout announces unfolded values per point.

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 | null)[]Series over time.
folds2 | 3Band count — 3 only when the range genuinely spans it.
mode"mirror" | "offset"Mirror flips negatives upward (denser); offset keeps up/down.
baselinenumberFold origin (e.g. a target level) — authored, never inferred.
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