Skip to content
microcharts
ReferenceExpressiveCometTrail

CometTrail

CometTrail marks the current value with a bright head dot and fades the recent positions behind it by age.

encodes
head position (now) + opacity-fading positional trail
precision
medium
nodes
trail + 2

CometTrail plots the current value as a bright head dot, with recent points trailing behind it and fading with age. In the interactive entry the head eases to each new value and the old head steps down into the trail, so a live stream draws a comet and a stall goes still. Opacity encodes age only; the y position carries the value. The trail is recency context, not data you have to decode.

CometTrail
interactive · 5.08 kB · static · 2.45 kB

Install

Import & usereact/comet-trail
import { CometTrail } from "@microcharts/react/comet-trail";// rollingWindow — real values under “Sample data” below<CometTrail data={rollingWindow} title="Latency" />
Sample data
const rollingWindow = [40, 45, 50, 55, 60, 65, 70, 72, 75, 78, 80, 84, 87];
Needs package + stylesheetSet up with AI

Try it

Motion, and reduced motion

Motion happens only on a data change; there is no idle loop. When a new value arrives the head eases (~200 ms, the library's canonical strong ease-out) from its old position to the new one, and the previous head steps down into the trail. A continuous stream produces the comet; a stalled stream goes still, which is itself the signal. The head never simulates phantom positions between updates: it eases to each real value. Under prefers-reduced-motion the head repositions instantly, since the static encoding is already complete. The same holds off-screen — one shared viewport check means the ease only runs while the chart is in view.

When to use it

Use it for a live price or metric with a little recency context, a realtime KPI that should show momentum, or per-stream "where is it now" in a table. For the full history or an exact multi-point comparison reach for Sparkline (or DotPlot); for discrete events, HeartbeatBlip.

Sizing

width and height are viewBox units that also set the rendered pixel box — they default to 60 × 16, sized to sit in a table cell or beside a line of text. Omit them and drive the width from CSS to fill a column; the viewBox keeps the aspect ratio. trail controls how many recent points the tail carries, which is a density decision rather than a size one. It is capped at 20: past that the trail stops being a trail and becomes a sparkline, which is the better tool for the full history.

Variants

label="last" is on by default, so the head always prints its number. Changing trail gives you more or less recency context without changing the head read, because opacity encodes age and nothing else.

shorter trail, or no numeral

Edge cases

empty
single point
trail longer than the data

Empty data draws just the frame, with "No data." as the summary. A single point has no trail to fade: the head alone, and "Now 52." A trail larger than the data never backfills or pads. It shows every point there is.

Four homes

Accessibility

The accessible name is the now-value and the recent trend: "Now 62, rising over the last 3 updates." With a single point it is the value alone, as in the edge case above: "Now 52." Arrow keys step back through the trail ("3 updates ago: 78.") and return toward now. Motion is gated on prefers-reduced-motion, and no reading depends on decoding the fade.

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[]The rolling window, oldest → newest (last = now).
trailnumberPoints kept visible (default 12, cap 20).
label"last" | "none"Numeral after the head (default last).
fontSizenumberType size of the numeral after the head, 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