Audio player
Read-aloud and audio output player: play and pause, a seek bar you can drag or step with keys, time in tabular figures, speed, and a compact mini player for message actions.
On this page
Speech is prepared, then plays with a seek bar and a speed menu.
Installation
Usage
import { AudioPlayer } from "@/components/ui/chatcn/audio-player"
<AudioPlayer src="/speech/answer-142.mp3" title="Why the deploy failed" meta="Marlo" />Speech engines that stream audio without a file drive the player instead: pass playing, currentTime and duration with their callbacks, and status while speech is generated.
<AudioPlayer
status={tts.ready ? "ready" : "loading"}
playing={tts.playing}
onPlayingChange={(play) => (play ? tts.resume() : tts.pause())}
currentTime={tts.position}
duration={tts.duration}
onSeek={tts.seek}
playbackRate={tts.rate}
onPlaybackRateChange={tts.setRate}
/>Examples
Variants and states
compact is the read-aloud button grown into a mini player, sized to sit in a row of message actions. peaks draws the track as a waveform with the played part in ink.
Compact mini player, waveform track, preparing, failed and ended.
States
| State | Shows |
|---|---|
loading | Spinner in the play button, Preparing audio, seek disabled |
ready | Play or pause |
buffering | A thin spinner ring around the pause button while playback stalls |
| Ended | Play again, which restarts from the beginning |
error | The reason with a fix, and Retry when onRetry is set |
Props
| Prop | Type | Notes |
|---|---|---|
src | string | Plays through an internal audio element |
title, meta | ReactNode | One line above the track in default |
variant | "default" | "compact" | Self-contained, or a mini player |
playing, defaultPlaying, onPlayingChange | boolean | Controlled or uncontrolled |
currentTime, onSeek | number (s) | Position, and seeks from the bar, keys and skip |
duration | number (s) | Read from the file when src is set |
playbackRate, defaultPlaybackRate, onPlaybackRateChange | number | Default 1 |
rates | number[] | Default 0.75, 1, 1.25, 1.5, 2 |
status | "loading" | "ready" | "buffering" | "error" | Derived from the element with src |
errorText, onRetry | ReactNode, () => void | Error copy should say how to fix it |
peaks | number[] | 0 to 1. Draws a waveform track |
skip | number | false | Skip back seconds. Default 10 |
onEnded, label | End callback; accessible name, default Audio player |
Keyboard
| Key | Action |
|---|---|
Space, K on the seek bar | Play or pause |
| Left and right arrows | Back or forward 5 seconds (mirrored in RTL) |
J, L | Back or forward 10 seconds |
Page Down, Page Up | Back or forward 30 seconds |
Home, End | Start or end |
| Arrow keys in the speed menu | Move between speeds; Enter picks |
Accessibility
- The player is a named group. The seek bar is a real
sliderwhose value is spoken in words: 1 minute 12 seconds of 3 minutes. - The play button's name follows its state: Play, Pause, Play again, Preparing audio. While preparing it is
aria-disabled, not removed from the tab order. - Errors are a
role=alertwith a red icon and words, never color alone. Touch targets grow to 44 px on coarse pointers.
Motion
- Play, pause and replay swap with a 150 ms blur crossfade when clicked; toggled with the keyboard they swap instantly.
- Progress moves with
transformandclip-pathonly, following the playhead every frame instead of the element's four updates a second. - The thumb fades in on hover, focus and drag over 150 ms. Under reduced motion the swap is instant.