Skip to content
microcharts
ReferenceFrontierWaveform

Waveform

Waveform compresses a signal with max-per-bucket so a single spike survives at word width.

encodes
mirrored bar height = per-bucket max amplitude
precision
medium
nodes
≤ 3
collection
Frontier
Source

Waveform buckets a high-frequency signal and draws each bucket's maximum, never its mean, so one spike survives the squeeze down to sparkline width. Averaging would erase the spike someone is looking for. The auto domain is symmetric at ±max|data|, and the peak is disclosed in the accessible summary.

Waveform
interactive · 5.23 kB · static · 2.62 kB

Install

Import & usereact/waveform
import { Waveform } from "@microcharts/react/waveform";// samples — real values under “Sample data” below<Waveform data={samples} title="Voice memo" />
Sample data
const samples = Array.from(  { length: 200 },  (_, i) =>    (i === 126 ? 0.82 : Math.sin(i / 3) * 0.15 + Math.sin(i / 11) * 0.35) *    (1 - Math.abs(i - 100) / 260),);
Needs package + stylesheetSet up with AI

Try it

Live playground
onActive
idle
  1. hover · rove · click…

Hover or arrow across the buckets — each announces its position and peak amplitude.

mode
mirror
progress % · 63
readout
animate
import { Waveform } from "@microcharts/react/waveform/interactive";// samples — real values under “Sample data” below<Waveform  data={samples}  progress={0.63}/>
Sample data
const samples = Array.from(  { length: 200 },  (_, i) =>    (i === 126 ? 0.82 : Math.sin(i / 3) * 0.15 + Math.sin(i / 11) * 0.35) *    (1 - Math.abs(i - 100) / 260),);

When to use it

Use it for voice-memo and audio scrubbers, and for high-frequency log or request volume. For exact values use Sparkline; for categorical state use Hypnogram.

Sizing

table cell
envelope

Variants

envelope
locale

With a locale, the announced peak follows that locale's own decimal mark: "0,82" in German, not "0.82".

Comparing loudness across rows needs an explicit shared domain. Without one, each chart fits its own max, and quiet data is rescaled to look loud.

Edge cases

one sample
silence

A single sample renders as one bucket, top-to-bottom. All-zero data renders every bucket at the shared 0.4-unit "silent" tick height, and the accessible summary says "Silent." rather than reporting a zero peak. A null behaves the same as a true zero for any bucket where it is the only sample: maxPerBucket skips non-finite values when picking the bucket's peak, and a bucket with nothing finite in it falls back to that same silence tick. A genuine gap and real silence therefore render identically here, unlike Sparkline's line break.

Four homes

In a sentence

Voice memo amplitude — peak 0.82 at 63%, 200 samples compressed to word width.

In a table cell
Standup memopeak 0.82 · 63%
Support callpeak 0.91 · 41%
Ambient roompeak 0.29 · 72%
In a KPI card
Voice memo
0.82peak amplitude · 63% through
In a tab header
Standup memoSupport callAmbient room

Preview uses the public chart API only. When an interactive twin exists, it swaps in with the same props and no entrance motion - code samples stay on the static import. Placement recipes: Composition, Sizing.

Accessibility

The accessible name discloses the peak: "Peak 0.398 at 50% through 200 samples." Pure silence reads "Silent." rather than blank. The interactive entry roves the buckets, announcing each bucket's position and peak amplitude.

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, press Escape, or press outside the chart. On touch, a tap pins and a drag scrubs.

Props

PropTypeNotes
data*number[]Amplitude samples; negatives allowed.
progressnumber0–1 played fraction; left buckets tint accent.
mode"bars" | "envelope"Envelope draws the min/max area.
mirrorbooleanMirror around center; false for magnitude-only.
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