Skip to content
microcharts
ReferenceExpressiveHeartbeatBlip

HeartbeatBlip

HeartbeatBlip draws one ECG-style spike per event in a rolling window, so a service's liveness and rate read together.

encodes
a spike per event across the recent window
precision
medium
nodes
3

HeartbeatBlip draws one ECG-style spike per event in a rolling window, 60 seconds by default, because liveness questions are about the last minute. In the interactive entry the trace sweeps left in real time and a new event blips in at the right edge, so the rate you see is the event rate. Every spike is one real event, never a synthesized pulse on a timer, and an empty window leaves a flat baseline: the down signal is carried by shape, not color.

Pass now from your data layer. The static entry never calls Date.now(), because a server render and the client hydrate would disagree and mismatch.

HeartbeatBlip
interactive · 4 kB · static · 2.42 kB

Install

Import & usereact/heartbeat-blip
import { HeartbeatBlip } from "@microcharts/react/heartbeat-blip";// pass 'now' from your data layer — never Date.now() in a server render// eventTimestamps, serverNow — real values under “Sample data” below<HeartbeatBlip events={eventTimestamps} now={serverNow} title="Requests" />
Sample data
const eventTimestamps = [97_000, 92_000, 85_000, 70_000, 55_000, 48_000];const serverNow = 100_000;
Needs package + stylesheetSet up with AI

Try it

Motion, and reduced motion

The trace advances in real time, so old spikes drift left and new events enter at the right. This is the deliberate idle-loop exception, allowed because the loop parameter (elapsed time) is the datum. It pauses off-screen through a shared observer, and under prefers-reduced-motion it does not sweep at all: the static strip re-renders on each data change instead, carrying the same information discretely. A flat service never gets a fake pulse. When the window empties, the baseline goes flat and stays flat.

When to use it

Use it for the liveness of a service or stream, a request rate in a header, or per-service liveness in a status table. For exact event counts use Seismogram or EventTimeline, for a continuous level BreathingDot, and for long-term trends Sparkline.

Sizing

width and height are viewBox units that also set the rendered pixel box — they default to 60 × 16, sized to sit in a status table row or a header. Omit them and drive the width from CSS to fill a column; the viewBox keeps the aspect ratio. window sets how much time the strip covers, which changes the density of the trace rather than its box.

Variants

count label, and the flatline down-signal
locale

format/locale only reach the label="count" numeral — the accessible summary's count is a plain integer (never run through the formatter), and the in-chart spikes never carry text, so there's nothing else to localize.

Edge cases

empty — the flat down-signal
non-finite timestamps are dropped, not drawn as spikes
events outside the window are dropped, not clamped

Four homes

Accessibility

The accessible name is the count, the window, and the time since the last event — "3 events in the last minute; last 3s ago." — or "No events in the last minute." when the trace is flat. Down and no-data are different states, and the summary distinguishes them. The trace sweeps only when motion is allowed and the chart is on-screen. The live region announces on data change, and there is no per-spike navigation, because the spikes are transient and the summary is the record.

This chart is a single unit, so there is nothing to rove between: a click, tap, Enter or Space selects it and fires onSelect, and no selection stays pinned. That is the scalar half of the shared interaction contract. Hover or focus also reveals the reading itself in a floating chip, for the sizes and label modes where the mark does not print it; readout={false} drops the chip and keeps everything else.

Props

PropTypeNotes
events*number[]Event timestamps (ms).
windownumberThe visible recent window in ms (default 60000).
nownumberExplicit clock — defaults to the latest event (SSR-safe).
label"count" | "none"Event-count numeral at the right.
fontSizenumberType size of the count numeral, in viewBox units. Defaults from `height`.

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