Hypnogram
Hypnogram draws which discrete state held over time as flat runs joined by right-angle steps.
- encodes
- row position (y = state, x = time), no interpolation
- precision
- high
- nodes
- ≤ 3 paths
Hypnogram draws which state a system was in over time: each state is a flat run at its own height, left to right, joined
by right-angle steps. There are no diagonals: a state holds until the next one, so a sloped line would invent readings
that never happened. Run lengths and the number of steps carry how choppy the period was. The states order sets the
vertical axis, and order is meaningful. Pass it explicitly for ordinal states like sleep depth or incident severity; for
nominal states with no rank, mode="lanes" keeps the axis from implying one.
Install
import { Hypnogram } from "@microcharts/react/hypnogram";// sleep — real values under “Sample data” below<Hypnogram data={sleep} states={["Awake","REM","Light","Deep"]} title="Sleep stages" />Sample data
const sleep = [ { t: 0, state: "Awake" }, { t: 8, state: "Light" }, { t: 22, state: "Deep" }, { t: 38, state: "Light" }, { t: 50, state: "REM" }, { t: 62, state: "Light" }, { t: 74, state: "Deep" }, { t: 86, state: "Light" }, { t: 98, state: "REM" }, { t: 110, state: "Awake" },];Try it
When to use it
Use it for sleep stages and for deploy, machine, or incident state over time. For continuous signals use Sparkline; for a single current state use StatusDot.
Sizing
Variants
Edge cases
A single entry holds its state across the whole domain. That is one flat run, and the summary names it directly: "1
state, no transitions; Deep throughout." A state present in the data but missing from an explicit states order is
never dropped. It is appended as its own row, with a dev-only console warning, so the strip accounts for every state it
is given.
Four homes
Accessibility
The accessible name states the shape: "3 transitions across 4 states; longest run Awake." The interactive entry roves the runs, and each announces its state and span ("Light, from 8 to 22."). Its entrance is a left-to-right clip reveal of the finished trace; smoothing or easing the step corners would change what the data says, so the steps are never interpolated.
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* | { t, state }[] | State holds from t to the next entry. |
| states | string[] | Row order top→bottom; ordinal semantics live here. |
| emphasis | string | Accents one state — the decision read. |
| mode | "steps" | "lanes" | Lanes for nominal states with no rank. |
| connectors | boolean | Vertical transition strokes (default true); off for ultra-dense strips. |
| labels | boolean | Left-gutter state names (default: on when width ≥ 96). |
| colors | string[] | Per-state lane colours (lanes mode), cycled; overrides --mc-cat-N. |
| 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.