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.
Install
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;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
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
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
| Prop | Type | Notes |
|---|---|---|
| events* | number[] | Event timestamps (ms). |
| window | number | The visible recent window in ms (default 60000). |
| now | number | Explicit clock — defaults to the latest event (SSR-safe). |
| label | "count" | "none" | Event-count numeral at the right. |
| fontSize | number | Type 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.