Skip to content

API & events

Construct with a selector or element and optional options:

const playlist = new WaveformPlaylist('#my-playlist', {
layout: 'list', // or 'minimal' | 'hero' | 'grid'
continuous: true,
waveformStyle: 'mirror', // any core player option passes through
height: 80
});

The constructor resolves the container, verifies window.WaveformPlayer, parses options and tracks, and — if any [data-track] was found — auto-initialises. It throws [WaveformPlaylist] Container element not found for a missing selector/element. With zero parsed tracks it constructs but does nothing further.

Method Description
selectTrack(index: number): void Load track index into the player via loadTrack(...); updates the active-row UI, resets currentChapterIndex to -1, and toggles which nested .wp-chapters block is visible. No-op if out of range.
seekToChapter(trackIndex: number, time: number): void Same track: seekTo(time) (and play() if paused). Cross-track: registers a ready callback, then selectTrack(trackIndex), seeking once the new track signals ready. No-op if trackIndex is out of range.
nextTrack(): void selectTrack(currentTrackIndex + 1) when not already on the last track.
previousTrack(): void selectTrack(currentTrackIndex - 1) when not already on the first track.
getPlayer(): WaveformPlayer | null The underlying player instance (null before init / after destroy()).
getCurrentTrackIndex(): number Zero-based index of the selected track.
getTracks(): WaveformPlaylistTrack[] The parsed track objects (element, index, url, title, artist, artwork, album, duration, chapters[], markers[]).
destroy(): void Removes the keydown listener, destroys the player, clears container.innerHTML, removes the waveform-playlist / wp-minimal classes, restores the hidden [data-track] elements, and nulls player / listElement / tracks.
WaveformPlaylist.init() (static) Auto-initialise every [data-waveform-playlist] not already marked initialised. Per-element errors are caught and console.error’d.
playlist.nextTrack();
playlist.seekToChapter(0, 330); // jump to 5:30 on track 0
const current = playlist.getCurrentTrackIndex();

The instance exposes (typed in index.d.ts): container, options, tracks[], currentTrackIndex, currentChapterIndex, player, and isPlaying.

A single, focus-scoped document keydown listener handles navigation. It only acts when this playlist’s container or its inner player holds focus, so multiple playlists on a page never cross-fire.

Key Action Condition
N Next track More than one track, and the playlist or its player has focus.
P Previous track More than one track, and the playlist or its player has focus.
19 Select track by number More than one track, and a playlist row (not the player) has focus.

Track rows (.wp-item), chapter rows (.wp-chapter, .wp-chapter-item) and minimal buttons (.wp-track-btn) are all keyboard-operable: rows expose role="button", join the tab order, and activate on click, Enter, or Space.

The playlist dispatches no custom DOM events of its own — it has no emit path. Instead it consumes the core player’s callbacks/events:

Source Effect
player onEnd Resets chapter highlight to the start; auto-advances to the next track if continuous and not on the last track.
player onTimeUpdate(current, total) Re-highlights the active chapter row (.wp-active + aria-current).
player onPlay Sets isPlaying = true, marks the active track, updates the artwork overlay icon to ti-player-pause.
player onPause Sets isPlaying = false, updates the overlay icon to ti-player-play; if paused at the end (current >= duration - 0.1) resets currentChapterIndex = -1 and re-highlights chapter 0.
player onLoad(player) Temporarily wrapped by the cross-track ready sequencing; the original onLoad is preserved and restored, and the callback fires exactly once.
waveformplayer:ready (capture) Primary cross-track “ready” signal; ready events whose detail.player is a different player are ignored.

To listen for player-level events (play, pause, seek, ended, etc.), attach to the player instance returned by getPlayer() — see the player events reference.

The playlist generates a structured DOM you can target for theming. Key hooks:

Class Element
.waveform-playlist The container (base styles), added on init. Layout modifiers: .wp-minimal, .wp-hero-layout, .wp-grid-layout, plus .wp-density-compact (density: 'compact') and .wp-cover-top (coverPosition: 'top').
.wp-player The generated player wrapper (list / minimal layouts). In the hero and grid layouts the embedded player renders into .wp-hero-stage instead.
.wp-list-container / .wp-list The list wrapper and the <ul> track list. .wp-chapters-only is the single-track-with-chapters variant.
.wp-item Track row (role="button"). .wp-active marks the active row.
.wp-indicator Track-number badge (shown when a track has no artwork).
.wp-artwork-container / .wp-artwork / .wp-artwork-overlay Artwork wrapper, image, and the active-track play/pause overlay.
.wp-info / .wp-title / .wp-artist / .wp-duration The text column.
.wp-chapters / .wp-chapter Nested chapter list and rows under a track (multi-track). .wp-chapter-time / .wp-chapter-label for the row contents.
.wp-chapter-item / .wp-time / .wp-label Rows in the single-track chapters-only list.
.wp-controls / .wp-track-btn Minimal-layout button container and buttons (aria-pressed reflects selection).
.wp-hero / .wp-hero-cover / .wp-hero-art / .wp-hero-overlay Hero — the “now playing” unit, the cover play/pause button, its image, and the overlay icon.
.wp-hero-stage / .wp-hero-meta / .wp-hero-title / .wp-hero-sub / .wp-hero-time Hero — the waveform stage (hosts the player) and the title / artist / current-total-time meta row.
.wp-queue / .wp-queue-item / .wp-queue-thumb / .wp-queue-state Hero — the stripped track queue: list, row, thumbnail, and the per-row play-state indicator.
.wp-now-bar / .wp-now-bar-top / .wp-now-meta Grid — the slim now-playing transport bar (.wp-now-bar-top when barPosition: 'top') and its title/time meta.
.wp-grid / .wp-grid-item / .wp-grid-cover / .wp-grid-art / .wp-grid-title Grid — the card container, a card (active card is ringed), the cover wrapper, image, and title.

Call destroy() when removing a playlist (e.g. in a SPA route change). It removes the keydown listener, destroys the inner player, wipes the generated UI, and restores your original [data-track] markup.

playlist.destroy();