Data attributes
Every data-* attribute, its option, and its type. Reference →
The fastest way to ship a waveform player: one stylesheet, one script, and a <div> with data-* attributes. No bundler, no build step, no framework. The library scans the page on load, finds every [data-waveform-player] element, and turns it into a player automatically.
Add the stylesheet in your <head>. The CSS is required — without it the player renders unstyled.
Add the script anywhere on the page. It exposes a global WaveformPlayer and auto-initialises on load.
Mark up a player with data-waveform-player plus a data-src pointing at your audio.
<!doctype html><html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1/dist/waveform-player.css" /> </head> <body> <div data-waveform-player data-src="/audio/track.mp3" data-title="Midnight Drive" data-artist="The Synthwave Collective" data-waveform-style="mirror" data-show-bpm="true" ></div>
<script src="https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1/dist/waveform-player.min.js" ></script> </body></html>That’s a complete, working player. The data-waveform-player attribute is the marker the library scans for; everything else is optional configuration. See Data attributes for the full list.
When the script loads it runs WaveformPlayer.init() for you:
DOMContentLoaded if the document is still parsing, or immediately if the document is already interactive (so placement in <head> or end-of-<body> both work).[data-waveform-player] element and constructs a WaveformPlayer for each one that isn’t already initialised.data-waveform-initialized="true" on it. This makes re-scanning idempotent — calling WaveformPlayer.init() again never double-initialises.If you inject markup after the initial load (AJAX, a modal, a client-side route change), call init() again to pick up the new elements. Already-initialised players are left untouched.
<script> // After inserting new [data-waveform-player] markup into the DOM: WaveformPlayer.init();</script>deferThe bundle is a self-contained IIFE that assigns window.WaveformPlayer. Both of these are valid:
<!-- End of <body>: document is parsed, init runs immediately --><script src="…/waveform-player.min.js"></script>
<!-- In <head> with defer: runs after parse, before DOMContentLoaded --><script defer src="…/waveform-player.min.js"></script>After auto-init, every player is reachable through static lookups on the global — no need to hold a reference. Pass an element, an element id, or the instance id.
<div id="hero" data-waveform-player data-src="/audio/track.mp3"></div>
<script> const player = WaveformPlayer.getInstance('hero');
player.container.addEventListener('waveformplayer:ended', (e) => { console.log('finished', e.detail.url); });
document.querySelector('#next').addEventListener('click', () => { player.loadTrack('/audio/next.mp3', 'Next Up'); });</script>| Static helper | Returns |
|---|---|
WaveformPlayer.getInstance(idOrElement) |
The matching instance, or undefined. |
WaveformPlayer.getAllInstances() |
Every live instance. |
WaveformPlayer.init() |
Re-scans the DOM and initialises new players. |
WaveformPlayer.destroyAll() |
Tears down every instance. |
WaveformPlayer.utils |
Shared pure helpers (formatTime, extractTitleFromUrl, escapeHtml, isSafeHref, parseDataAttributes). |
See Methods and Events for the complete surface.
You don’t have to use data-*. The same global works as a constructor — useful when you want options computed in JavaScript:
<div id="player"></div>
<script> const player = new WaveformPlayer('#player', { url: '/audio/track.mp3', waveformStyle: 'mirror', waveformColor: ['#fafafa', '#71717a'], // vertical gradient stops showBPM: true, onTimeUpdate: (currentTime, duration, p) => { /* … */ }, });</script>Options merge in precedence order defaults < data-* < constructor options, so a JS option always wins over the same data-* attribute on the element.
The package publishes a minified IIFE bundle and a stylesheet. Pin to a major version (@1) for automatic patch/minor updates, or pin an exact version for fully reproducible builds.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1/dist/waveform-player.css" /><script src="https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1/dist/waveform-player.min.js"></script><link rel="stylesheet" href="https://unpkg.com/@arraypress/waveform-player@1/dist/waveform-player.css" /><script src="https://unpkg.com/@arraypress/waveform-player@1/dist/waveform-player.min.js"></script>dist/| File | Use |
|---|---|
waveform-player.min.js |
Minified IIFE for <script> / CDN. Exposes window.WaveformPlayer. The package’s unpkg default. |
waveform-player.js |
Unminified IIFE (same global) — handy while debugging. |
waveform-player.css |
Required stylesheet. Also exported as @arraypress/waveform-player/styles.css. |
waveform-player.esm.js |
ES module build for bundlers / import. |
waveform-player.cjs |
CommonJS build for require. |
The ESM and CJS builds are for bundler installs — for plain HTML you want waveform-player.min.js plus the CSS.
The bar and playlist extensions are thin layers over the core player. At load time each one checks for window.WaveformPlayer and aborts if it’s missing:
@arraypress/waveform-bar logs [WaveformBar] WaveformPlayer is required.@arraypress/waveform-playlist throws [WaveformPlaylist] WaveformPlayer is required but not found.So the rule is simple: load the core player first, then any extension.
<head> <!-- Core player styles + any extension styles --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1/dist/waveform-player.css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@arraypress/waveform-bar@1/dist/waveform-bar.css" /></head><body> <!-- … your players / triggers … -->
<!-- 1. Core player — defines window.WaveformPlayer --> <script src="https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1/dist/waveform-player.min.js"></script>
<!-- 2. Extension — consumes window.WaveformPlayer --> <script src="https://cdn.jsdelivr.net/npm/@arraypress/waveform-bar@1/dist/waveform-bar.min.js"></script></body>Stylesheet order doesn’t matter for correctness, but keep the core stylesheet present whenever any extension is on the page — the extensions render core players and rely on its classes. Continue with Bottom bar or Playlist for each extension’s markup and triggers.
Prefer not to depend on a third-party CDN? Vendor the files into your own project. Install the package, then copy the two files you need out of dist/.
npm install @arraypress/waveform-playerpnpm add @arraypress/waveform-playeryarn add @arraypress/waveform-playerbun add @arraypress/waveform-playermkdir -p public/vendor/waveform-playercp node_modules/@arraypress/waveform-player/dist/waveform-player.min.js public/vendor/waveform-player/cp node_modules/@arraypress/waveform-player/dist/waveform-player.css public/vendor/waveform-player/Then reference the local copies — identical markup, local paths:
<link rel="stylesheet" href="/vendor/waveform-player/waveform-player.css" /><!-- … --><script src="/vendor/waveform-player/waveform-player.min.js"></script>No package manager? Download the same files straight from a CDN (these URLs serve the raw artifacts):
curl -O https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1.14.0/dist/waveform-player.min.jscurl -O https://cdn.jsdelivr.net/npm/@arraypress/waveform-player@1.14.0/dist/waveform-player.cssData attributes
Every data-* attribute, its option, and its type. Reference →
Options
The full configuration surface, JS and declarative. Reference →
Methods
loadTrack, seekTo, static lookups, and more. Reference →
Events
waveformplayer:* events and option callbacks. Reference →