Skip to main content

Components

Pre-built React components for building audio applications.

Import​

import {
Waveform,
PlayButton,
PauseButton,
StopButton,
// ... other components
} from '@waveform-playlist/browser';

Waveform​

The main visualization component that renders tracks and handles interactions.

<Waveform />

Features​

  • Canvas-based waveform rendering
  • Click to seek
  • Drag to select
  • Drag clips to move/trim
  • Keyboard shortcuts
  • Custom playhead rendering

Props​

PropTypeDefaultDescription
timescalebooleanfalseShow timeline with time markers
showClipHeadersbooleanfalseShow clip name headers above waveforms
renderPlayheadRenderPlayheadFunction-Custom playhead render function
renderTrackControls(trackIndex: number) => ReactNode-Custom track controls renderer

Usage​

<WaveformPlaylistProvider tracks={tracks}>
<Waveform />
</WaveformPlaylistProvider>

The Waveform component reads configuration from the provider context.


Custom Playhead​

Replace the default playhead with a custom component using the renderPlayhead prop.

PlayheadProps​

The render function receives these props:

interface PlayheadProps {
/** Position in pixels from left edge */
position: number;
/** Playhead color from theme (default: #ff0000) */
color?: string;
}

Built-in Playhead Components​

Import pre-built playhead variants:

import { Playhead, PlayheadWithMarker } from '@waveform-playlist/ui-components';

Default Playhead​

A simple vertical line (used by default):

<Waveform />
// or explicitly:
<Waveform renderPlayhead={(props) => <Playhead {...props} />} />

PlayheadWithMarker​

A playhead with a triangle marker at the top, positioned to sit in the timescale area:

<Waveform
timescale
renderPlayhead={(props) => <PlayheadWithMarker {...props} />}
/>

Custom Playhead Example​

Create your own playhead component:

import styled from 'styled-components';

const CustomPlayheadLine = styled.div<{ $position: number; $color: string }>`
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 100%;
background: ${(props) => props.$color};
transform: translate3d(${(props) => props.$position}px, 0, 0);
z-index: 150;
pointer-events: none;
will-change: transform;
border-radius: 2px;
box-shadow: 0 0 4px ${(props) => props.$color};
`;

const GlowingPlayhead = ({ position, color = '#ff0000' }) => (
<CustomPlayheadLine $position={position} $color={color} />
);

// Usage
<Waveform renderPlayhead={(props) => <GlowingPlayhead {...props} />} />

Performance Tips​

  • Use transform: translate3d() for GPU-accelerated positioning
  • Add will-change: transform for smooth animation
  • Set pointer-events: none to prevent interference with track interactions

Playback Buttons​

PlayButton​

Starts playback from the current cursor position.

<PlayButton />

Behavior:

  • Disabled during playback
  • Starts from selection start if selection exists

PauseButton​

Pauses playback, maintaining cursor position.

<PauseButton />

Behavior:

  • Disabled when not playing

StopButton​

Stops playback and resets cursor to start.

<StopButton />

Behavior:

  • Always enabled

RewindButton​

Jumps backward by a fixed amount.

<RewindButton />

Default: 5 seconds

FastForwardButton​

Jumps forward by a fixed amount.

<FastForwardButton />

Default: 5 seconds

SetLoopRegionButton​

Creates a loop region from the current selection, or clears an existing loop region.

<SetLoopRegionButton />

Behavior:

  • Disabled when no selection exists and no loop region is set
  • Shows "Set Loop" when no loop region exists
  • Shows "Clear Loop" when a loop region is set
  • Click to toggle between setting and clearing the loop region

LoopButton​

Toggles loop mode for the loop region.

<LoopButton />

Behavior:

  • Shows "Loop Off" when disabled, "Loop On" when enabled
  • If no loop region exists when enabling, creates a default loop region (first 10s or 25% of duration)
  • When enabled, playback loops when the cursor enters and reaches the end of the loop region
  • Loop region is displayed in the timescale area and can be dragged to adjust

Workflow:

  1. Create a selection by clicking and dragging on the waveform
  2. Click SetLoopRegionButton to create a loop region from the selection (or drag in the timescale)
  3. Click LoopButton to enable looping
  4. Play - when the cursor reaches the loop region, it will loop

Zoom Controls​

ZoomInButton​

Decreases samplesPerPixel for more detail.

<ZoomInButton />

Behavior:

  • Disabled at minimum zoom (128 spp)

ZoomOutButton​

Increases samplesPerPixel for wider view.

<ZoomOutButton />

Behavior:

  • Disabled at maximum zoom (8192 spp)

Volume Controls​

MasterVolumeControl​

Slider for overall output volume.

<MasterVolumeControl />

Range: 0 (silent) to 1 (full)

TrackVolumeControl​

Volume slider for a specific track.

<TrackVolumeControl trackIndex={0} />

Props:

  • trackIndex (required): Index of the track

Position Display​

AudioPosition​

Shows current time and duration.

<AudioPosition />
// Output: "0:00.000 / 3:45.123"

The format respects the current time format setting.


Time Format​

TimeFormatSelect​

Dropdown for selecting time display format.

<TimeFormatSelect />

Options:

  • seconds - 0.000
  • thousandths - 0:00.000
  • hh:mm:ss - 0:00:00
  • hh:mm:ss.u - 0:00:00.0
  • hh:mm:ss.uu - 0:00:00.00
  • hh:mm:ss.uuu - 0:00:00.000

Checkboxes​

ContinuousPlayCheckbox​

Toggle for loop mode.

<ContinuousPlayCheckbox />

AutomaticScrollCheckbox​

Toggle for auto-scrolling during playback.

<AutomaticScrollCheckbox />

Track Controls​

TrackControls​

Built-in control panel for a track.

<TrackControls trackIndex={0} />

Includes:

  • Track name
  • Mute button
  • Solo button
  • Volume slider
  • Pan slider

TrackControlsWithDelete​

TrackControls with a delete button.

<TrackControlsWithDelete
trackIndex={0}
onDelete={() => removeTrack(0)}
/>

Props:

  • trackIndex (required): Track index
  • onDelete (required): Delete callback

Export Controls​

ExportWavButton​

Export the playlist to a WAV file.

<ExportWavButton />

Props:

PropTypeDefaultDescription
labelstring'Export WAV'Button label
filenamestring'export'Downloaded file name (without extension)
mode'master' | 'individual''master'Export all tracks mixed or single track
trackIndexnumber-Track index for individual export
bitDepth16 | 3216WAV bit depth (16-bit PCM or 32-bit float)
applyEffectsbooleantrueApply fades and other clip effects
effectsFunctionEffectsFunction-Tone.js effects chain for export with effects
classNamestring-CSS class name
onExportComplete(blob: Blob) => void-Callback when export succeeds
onExportError(error: Error) => void-Callback when export fails

Behavior:

  • Shows progress percentage during export
  • Disabled when no tracks loaded
  • Automatically triggers download when complete

Example:

<ExportWavButton
filename="my-mix"
mode="master"
bitDepth={16}
onExportComplete={(blob) => console.log('Exported:', blob.size, 'bytes')}
/>

Individual Track Export:

<ExportWavButton
label="Export Track 1"
filename="track-1"
mode="individual"
trackIndex={0}
/>

Export Without Effects (Raw Audio):

<ExportWavButton
label="Export Raw"
filename="raw-export"
applyEffects={false}
/>

Export With Tone.js Effects:

import { Reverb } from 'tone';

// Define effects chain
const createEffectsChain = (masterVolume, destination, isOffline) => {
const reverb = new Reverb({ decay: 2.5, wet: 0.3 });
masterVolume.connect(reverb);
reverb.connect(destination);

// Return cleanup function
return () => {
reverb.dispose();
};
};

// Use in export button
<ExportWavButton
label="Export with Reverb"
filename="mix-with-effects"
effectsFunction={createEffectsChain}
/>

Complete Example​

import {
WaveformPlaylistProvider,
Waveform,
PlayButton,
PauseButton,
StopButton,
RewindButton,
FastForwardButton,
SetLoopRegionButton,
LoopButton,
ZoomInButton,
ZoomOutButton,
MasterVolumeControl,
AudioPosition,
TimeFormatSelect,
ContinuousPlayCheckbox,
AutomaticScrollCheckbox,
ExportWavButton,
useAudioTracks,
} from '@waveform-playlist/browser';

function FullFeaturedPlaylist() {
const { tracks, loading, error } = useAudioTracks([
{ src: '/audio/track1.mp3', name: 'Track 1' },
{ src: '/audio/track2.mp3', name: 'Track 2' },
]);

if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;

return (
<WaveformPlaylistProvider
tracks={tracks}
samplesPerPixel={1024}
waveHeight={100}
timescale
controls={{ show: true, width: 180 }}
>
{/* Transport Controls */}
<div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem' }}>
<RewindButton />
<PlayButton />
<PauseButton />
<StopButton />
<FastForwardButton />
<SetLoopRegionButton />
<LoopButton />
</div>

{/* Zoom Controls */}
<div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem' }}>
<ZoomInButton />
<ZoomOutButton />
</div>

{/* Volume and Position */}
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center', marginBottom: '1rem' }}>
<MasterVolumeControl />
<AudioPosition />
<TimeFormatSelect />
</div>

{/* Options */}
<div style={{ display: 'flex', gap: '1rem', marginBottom: '1rem' }}>
<ContinuousPlayCheckbox />
<AutomaticScrollCheckbox />
</div>

{/* Export */}
<div style={{ marginBottom: '1rem' }}>
<ExportWavButton filename="my-mix" />
</div>

{/* Waveform */}
<Waveform />
</WaveformPlaylistProvider>
);
}

Styling Components​

All components accept standard React props including className and style:

<PlayButton className="my-play-button" />
<PlayButton style={{ backgroundColor: 'green' }} />

For consistent styling, use the theme system or wrap components:

const StyledPlayButton = styled(PlayButton)`
background: #0066cc;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;

&:hover {
background: #0055aa;
}

&:disabled {
background: #cccccc;
cursor: not-allowed;
}
`;

See Also​

Buy Me A Coffee