Audio Player

A player built on the real <audio> element, so buffering, codecs, media keys, the OS lock screen and Bluetooth controls all keep working. State is read back off the element rather than mirrored, so anything else touching playback stays in sync.

src/components/ui/audio-player.tsx

About

From the component's own source, where it was written.

An audio element with a scrubber, built on the real <audio> element.

The element does the work — buffering, codecs, media keys, the OS lock screen, Bluetooth controls — and this draws the surface over it. A player built on AudioContext for the sake of a nicer waveform loses all of that, and the waveform is the least important part.

**State is read from the element, not mirrored beside it.** timeupdate, play and pause all fire whether the change came from this UI, a media key, or the OS — so mirroring into React state means the two disagree the moment anything else touches playback.

**The scrubber is the kit's Slider.** It is a range input underneath, so keyboard seeking, page-up jumps, screen-reader announcement and touch drag are all native — and it looks like every other slider in the product, which a hand-styled one with its own vendor pseudo-element rules did not. It is scrubbing *while dragging* that needs care: dragging suspends the timeupdate handler, or every frame of playback yanks the thumb back out of your hand.

peaks draws a waveform behind the track when you have one, and the slider's rail and fill go transparent so the peaks *are* the track rather than being covered by a second progress bar. Computing it here would mean decoding the whole file in the main thread before the first frame — the caller either has it precomputed or does not want it.

Install

npx astralyx-ui add audio-player

Usage

import { AudioPlayer } from '@/components/ui/audio-player'

<AudioPlayer src="/theme.mp3" title="Theme" artist="Astralyx" peaks={peaks} />

Composer

Change the props and the source below follows.

For bigger joyrides

Sample audio

0:00
0:00
Props
tsx
<AudioPlayer
  src="/theme.mp3"
  title="Theme"
  artist="Astralyx"
  showSkip={true}
  peaks={peaks}
/>

Examples

With a waveform

Bare

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

AudioPlayer

Extends Omit<ComponentProps<'div'>, 'title' | 'onEnded'>.

PropTypeDefaultDescription
srcstringrequiredThe element does the playing; this draws the surface over it.
titleReactNode—The element does the playing; this draws the surface over it.
artistReactNode—The element does the playing; this draws the surface over it.
peaksnumber[]—Precomputed amplitudes 0–1, drawn behind the scrubber. Computing them here would mean decoding the whole file on the main thread before the first frame.
defaultMutedbooleanfalseStart muted — required for anything that also autoplays.
skipBynumber15Seconds a skip button moves, and whether they render at all.
showSkipbooleantrueSeconds a skip button moves, and whether they render at all.
artworkReactNode—Cover art.
onEnded() => void——
playLabelstring'Play'—
pauseLabelstring'Pause'—
muteLabelstring'Mute'—
unmuteLabelstring'Unmute'—
seekLabelstring'Seek'—
backLabelstring'Back'—
forwardLabelstring'Forward'—
formatTime(seconds: number) => stringdefaultTimeFormats the clock. Defaults to m:ss, and h:mm:ss past an hour.

Functions

FunctionSignatureDescription
formatAudioTime(seconds: number) => string—

Behaviour

TopicDetailDescription
scrubbinginput[type=range]Keyboard seeking, page-up jumps and screen-reader announcement are native. timeupdate is suspended while dragging, or playback yanks the thumb out of your hand.
stateread from the elementEvery listener reads back off <audio>, so a media key or the OS lock screen keeps this UI correct without going through it.