Skip to content
microcharts
ReferenceCoreHorizon

Horizon

Horizon folds a wide-range series into bands so magnitude reads as layer opacity in a row a few pixels tall.

encodes
position + fold-layer opacity (darker = higher band)
precision
low — a density read; Sparkline when exact shape matters
nodes
≤ 6 (≤ 3 fold paths per direction)

Horizon prints a whole wide-range series in a 14-pixel row. It cuts the series into bands and folds them, so layer opacity carries magnitude and extremes stay visible at heights where a sparkline would flatten into noise. Two folds is the default, because two read approximately without training; three trade learnability for density, so reserve them for ranges that genuinely span them.

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.22 kB · static · 2.88 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

Use it for dense monitoring rows (dozens stacked) and wide-range series in tight cells. Folding needs a key, so skip it for first-glance audiences; with a few rows and room to spare, use Sparkline.

Sizing

Variants

three folds
fold around a target

baseline is authored, never inferred: a fold origin is a claim about what "normal" means.

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 density means distance from the baseline rather than 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

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