@arraypress/waveform-playlist-svelte
Svelte 5 component wrapper around @arraypress/waveform-playlist. Declarative tracks (with chapters + markers), typed props for every playlist + player option, and an exported imperative navigation API (selectTrack() / nextTrack() / previousTrack()).
The core library stays a zero-dependency vanilla-JS package that works anywhere a <script> tag does. This package adds the framework-native ergonomics Svelte developers expect — built with runes.
<script lang="ts">
import { WaveformPlaylist } from '@arraypress/waveform-playlist-svelte';
const tracks = [
{ url: '/audio/a.mp3', title: 'Track A' },
{ url: '/audio/b.mp3', title: 'Track B' },
];
</script>
<WaveformPlaylist {tracks} />Installation
npm install @arraypress/waveform-playlist-svelte @arraypress/waveform-playlist @arraypress/waveform-player sveltesvelte (^5), @arraypress/waveform-playlist (^1.3), and @arraypress/waveform-player (^1.8) are peer dependencies.
Setup
Import both cores' CSS once in your app entry, and ensure the core player is loaded (the playlist instantiates window.WaveformPlayer for the active track):
import '@arraypress/waveform-player'; // registers window.WaveformPlayer
import '@arraypress/waveform-player/dist/waveform-player.css';
import '@arraypress/waveform-playlist/dist/waveform-playlist.css';The wrapper does not import CSS for you. The playlist's JS is loaded dynamically inside a $effect (browser-only), so SSR / SvelteKit prerendering doesn't trip over the browser-only audio APIs.
Usage
Tracks with metadata + chapters
<script lang="ts">
import { WaveformPlaylist, type WaveformPlaylistTrackInput } from '@arraypress/waveform-playlist-svelte';
const tracks: WaveformPlaylistTrackInput[] = [
{
url: '/audio/episode-1.mp3',
title: 'Episode 1',
artist: 'The Pilot',
artwork: '/img/ep1.jpg',
duration: '42:10',
chapters: [
{ time: 0, label: 'Cold open' },
{ time: 90, label: 'Main topic', color: '#a855f7' },
{ time: '38:00', label: 'Wrap-up' },
],
},
{ url: '/audio/episode-2.mp3', title: 'Episode 2' },
];
</script>
<WaveformPlaylist {tracks} layout="list" continuous showDuration />Naming note.
class,style,id, and other element attributes fall through to the host element; the base classwfp-hostis always applied. The visual style iswaveformStyle.
Imperative navigation via bind:this
<script lang="ts">
import { WaveformPlaylist } from '@arraypress/waveform-playlist-svelte';
let playlist: WaveformPlaylist;
</script>
<WaveformPlaylist bind:this={playlist} {tracks} />
<button onclick={() => playlist.previousTrack()}>Prev</button>
<button onclick={() => playlist.nextTrack()}>Next</button>
<button onclick={() => playlist.selectTrack(2)}>Track 3</button>The exported methods (selectTrack(), seekToChapter(), nextTrack(), previousTrack(), getPlayer(), getCurrentTrackIndex(), getTracks()) pass straight through to the underlying instance. playlist.getInstance() returns the raw instance.
How it works
Tracks are rendered declaratively into the [data-track] / [data-chapter] markup the WaveformPlaylist constructor parses on mount — the same contract the vanilla library uses. When any construction prop changes (a serialised tracks change, layout, options, …), the wrapper destroys the instance and rebuilds it over the freshly-rendered markup.
There are no lifecycle callbacks — the playlist owns the embedded player's callbacks internally to drive continuous playback and chapter tracking. Observe playback via the embedded player from getPlayer().
Props
Every playlist option and forwarded player option is a typed prop; absent props are not forwarded, so the cores' own defaults apply. See src/lib/types.ts. Highlights: tracks (required), layout, continuous, expandChapters, showDuration, showChapterMarkers, chapterMarkerColor, showPlayState, plus the player surface (waveformStyle, height, samples, barWidth, colorPreset, colours, playbackRate, showControls, showInfo, showTime, showBPM, accessibleSeek, …).
TypeScript
import type {
WaveformPlaylistProps,
WaveformPlaylistExpose,
WaveformPlaylistTrackInput,
WaveformPlaylistChapterInput,
WaveformPlaylistOptions,
WaveformPlaylistTrack,
WaveformStyle,
ColorPreset,
} from '@arraypress/waveform-playlist-svelte';Types are re-exported straight from the cores, so they can never drift. The package ships .svelte + .d.ts (generated by svelte-package).
Testing
npm test # one-shot
npm run typecheck # svelte-check
npm run build # svelte-package → dist/The core library is mocked at the module boundary (jsdom has no Web Audio API).
License
MIT ArrayPress