Waveform
Real-time audio visualization with a smooth scrolling bar “wave”. Uses Web Audio (AudioContext + AnalyserNode) and draws to a <canvas>.
Preview
"use client";
import { Waveform } from "@/registry/waveform";
export function WaveformDemo() {
return (
<div className="flex w-full max-w-md flex-col gap-3">
<Waveform className="h-14 rounded-lg" />
</div>
);
}
Installation
pnpm dlx @arrowui/cli@latest add waveformUsage
import { Waveform } from "@/registry/waveform";<Waveform />By default, Waveform will request microphone access while it is mounted and active is true.
Recommended pattern
Gate active behind a user gesture (button click). This prevents surprise permission prompts on page load.
"use client";
import * as React from "react";
import { Waveform } from "@/registry/waveform";
export function MicWaveform() {
const [active, setActive] = React.useState(false);
return (
<div className="flex flex-col gap-3">
<button type="button" onClick={() => setActive((v) => !v)}>
{active ? "Stop" : "Start mic"}
</button>
<Waveform active={active} />
</div>
);
}External audio streams
If you already have a MediaStream (WebRTC call audio, a recorder, etc.), pass it via stream:
<Waveform stream={myMediaStream} active />stream={undefined}:Waveformwill create its own microphone stream (default).stream={MediaStream}:Waveformuses your stream and will not callgetUserMedia.stream={null}: disables audio (renders nothing / clears the canvas).
Examples
Strength
Use the strength prop to tune how reactive the bars feel.
Soft (strength=0.6)
Default (strength=1)
Hot (strength=1.6)
"use client";
import { Waveform } from "@/registry/waveform";
export function WaveformStrengthDemo() {
return (
<div className="flex w-full max-w-md flex-col gap-4">
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Soft (strength=0.6)
</div>
<Waveform className="h-10 rounded-md" strength={0.6} />
</div>
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Default (strength=1)
</div>
<Waveform className="h-10 rounded-md" />
</div>
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Hot (strength=1.6)
</div>
<Waveform className="h-10 rounded-md" strength={1.6} />
</div>
</div>
);
}
Density
Tune bar density with barWidthPx, gapPx, and bars (cap).
Dense (1px bars, 1px gap)
Default (2px bars, 2px gap)
Chunky (3px bars, 3px gap)
"use client";
import { Waveform } from "@/registry/waveform";
export function WaveformDensityDemo() {
return (
<div className="flex w-full max-w-md flex-col gap-4">
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Dense (1px bars, 1px gap)
</div>
<Waveform
className="h-10 rounded-md"
barWidthPx={1}
gapPx={1}
bars={160}
/>
</div>
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Default (2px bars, 2px gap)
</div>
<Waveform className="h-10 rounded-md" />
</div>
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Chunky (3px bars, 3px gap)
</div>
<Waveform
className="h-10 rounded-md"
barWidthPx={3}
gapPx={3}
bars={72}
/>
</div>
</div>
);
}
Track + color
Pass backgroundColor to render a solid “track” behind the bars.
Dark track + light bars
Subtle track + charcoal bars
"use client";
import { Waveform } from "@/registry/waveform";
export function WaveformTrackDemo() {
return (
<div className="flex w-full max-w-md flex-col gap-4">
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Dark track + light bars
</div>
<Waveform
className="h-10 rounded-md"
backgroundColor="#121212"
barColor="rgba(255,255,255,0.85)"
/>
</div>
<div className="flex flex-col gap-1">
<div className="text-xs font-medium text-muted-foreground">
Subtle track + charcoal bars
</div>
<Waveform
className="h-10 rounded-md"
backgroundColor="rgba(0,0,0,0.06)"
barColor="rgba(48,48,48,0.75)"
/>
</div>
</div>
);
}