AudioPlayer
StablePlays one clip: play and pause, a waveform to seek, time, speed and download.
Also known as audio, player, media player
Install with npm install @tattva/ui (setup), or copy the code from the kit in Downloads.
Call recording
Support call, 3 October, 14:02
<AudioPlayer
title="Call with Maya Okafor"
subtitle="Support call, 3 October, 14:02"
duration={192}
peaks={peaks}
markers={[
{ at: 41, label: "Tool call: look up order 4471" },
{ at: 96, label: "Caller interrupted the assistant" },
{ at: 158, label: "Transfer to a person, check the reason", tone: "review" },
]}
onDownload={download}
/>
// With a real file, the length comes from the file:
<AudioPlayer title="Call with Maya Okafor" src="/recordings/4471.mp3" peaks={peaks} />No file is needed for a preview: the player simulates playback from duration. Press Play, then try the arrow keys on the waveform, or Space and K anywhere in the player.
When to use it
Lets someone listen back, jump to a moment and change the speed, with every state written in words.
Made of: Play button · Title · AI label · Subtitle or state · Waveform · Time · Speed · Download
Use it for
- Listening back to a support or sales call.
- Playing a voice or song the AI made, with an AI label.
- A list of short takes, using the compact row.
Not for
- A live conversation with the assistant: use VoicePanel.
- A recording with a transcript that follows along: use TranscriptSync.
- Video: use MediaFrame.
Do and avoid
Ready
Ready
Do
- Wait for a press before playing anything.
- Mark only the moments people need, such as tool calls, interruptions and the end.
- Say why a clip cannot be played or downloaded, and what is still there.
- Add the AI label to clips the AI made, and keep the rest of the player neutral.
Avoid
- Don't autoplay, or play a preview on hover.
- Don't colour the waveform or the Play button with the AI colour.
- Don't let two players play at once. This one pauses the others for you.
- Don't use amber for "recording" or "new take ready". Neither needs a person to act.
On a phone
- The Play button is 44px. Speed and Download grow to 44px tall on touch screens.
- The seek area is at least 44px tall. Tap to seek, and a time bubble shows while dragging.
- The bottom row wraps when space is short. On the narrowest phones the waveform becomes a plain bar.
- While playing it sets the lock-screen title and play, pause and seek controls where the browser supports them.
- The compact row is 56px tall.
Seen in products
- Vapi call logs have a waveform you can play and scrub, with downloads for mono, stereo or each side.
- Alexa voice history lets you play each recording.
- NotebookLM audio overviews offer playback speed, download, feedback and an AI label.
- Suno limits downloads per month and shows how many are left.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
| titlerequired | string | none | Title of the clip. Also names the player region. |
| subtitle | string | none | Second line, such as the date. Without it the line shows the state in words. |
| src | string | none | A real audio file. Leave out to simulate playback from duration. |
| duration | number | none | Length in seconds. Needed without src. |
| peaks | number[] | null | none | Loudness per slice for the waveform. null shows it still drawing. Leave out for a plain bar. |
| state | "loading" | "streaming" | "buffering" | "error" | "unavailable" | none | Forces a state the player cannot see. Ready, playing, paused and ended are tracked by the player. |
| current | number | none | Position in seconds when the parent keeps it. A change of more than a quarter second seeks. |
| onTimeChange | (seconds: number) => void | none | Called as the position moves. |
| onPlayingChange | (playing: boolean) => void | none | Called when playback starts or stops. |
| markers | WaveformMarker[] | none | Moments on the timeline. Passed to the Waveform. |
| regions | WaveformRegion[] | none | Marked stretches. Passed to the Waveform. |
| madeUpTo | number | none | In the streaming state, the seconds made so far. |
| speeds | number[] | [0.75, 1, 1.25, 1.5, 2] | Speeds offered. Pass one value to hide the choice. |
| aiGenerated | boolean | false | Adds an AI label beside the title. |
| aiNote | ReactNode | none | What the AI label explains, such as the voice and date. |
| onDownload | () => void | none | Shows a Download button. |
| downloadNote | string | none | Note beside Download, such as downloads left. |
| unavailableReason | string | none | Why it cannot be played, shown in the unavailable state. |
| errorText | string | "This audio could not be loaded." | Message in the error state. |
| onRetry | () => void | none | Shows Try again in the error state. |
| mediaSession | { artist?: string; artwork?: string } | none | Extra lock-screen details while playing. |
| compact | boolean | false | One 56px row for lists, with no waveform, speed or download. |
| className | string | none | Extra classes on the player. |
"Show code under the preview gives the code for the example on the stage."
In Figma
In Figma, one AudioPlayer switches all of this from its properties panel, across 20 variants. Each property sets the React prop beside it, so design and code use the same names.
| Figma property | React | Values |
|---|---|---|
| Status | state | Loading, Streaming, Buffering, Error, Unavailable |
| Ai generated | aiGenerated | On or off |
| Compact | compact | On or off |
| Title | title | Any text |
| Subtitle | subtitle | Any text |
States
States this part has beyond its default look. Build each one your screen can reach. States set by a property are in the Code tab.
- one at a time
- Starting any player pauses the others on the page.
Tokens
Change one of these and every part that uses it follows.
--accent--fg--fg-muted--border--surface--surface-sunken--danger-fg--dur-instant--text-compact--text-small
Built in
- The player is a region named by its title.
- Play is a toggle button named Play with aria-pressed, true while playing. When it cannot play it uses aria-disabled and stays focusable.
- Space and K play or pause while focus is in the player, but not in the speed choice or any text field, and Space on a button keeps its usual meaning.
- The waveform is a slider with the time in words, such as "52 seconds of 3 minutes 12 seconds"; see Waveform for its keys.
- Buffering, ended, streaming, error and unavailable are announced once through a status region. The clock is never announced.
- The time uses tabular figures, so it does not jitter.
- Speed is a native select named Playback speed.
- Under reduced motion the simulated clock ticks four times a second, so the playhead moves in steps.
What you need to do
- Give a title that tells clips apart, such as "Call with Maya Okafor". It names the player.
- Never start playback without a press. Autoplay talks over screen readers.
- Offer a transcript for recorded speech, with TranscriptSync or a link.
- Pass the error and unavailable reasons in plain words, and onRetry when trying again can help.
Built toward WCAG 2.2 AA and checked automatically; no independent audit yet. Read the accessibility guide