import {
AudioPlayer,
AudioPlayerControlBar,Everything you need to build an audio player is in a single file: the engine, the UI controls, the queue, tracks, and playback speed. No separate installs, no cross-file wiring. Just one component you copy, paste, and own.
Installation
pnpm dlx shadcn@latest add @audio/player
The CLI resolves every dependency automatically: the store, the HTML audio engine, Fader, Transport, SortableList, and the shadcn/ui primitives the player uses.
Philosophy
Composable by default. AudioPlayer is just a container. Every control (seek bar, volume, queue, playback speed) is an independent component you drop in where you need it. No black-box layout, no hidden markup.
State lives in the store, not in components. All playback state (current track, progress, queue, shuffle, repeat) is held in a Zustand store. Components read and write that store directly. No prop drilling, no context threading.
The engine is separate from the UI. AudioProvider wires up the HTML audio element to the store: event listeners, retries, preloading, state restoration. UI components just read state and call store actions.
Setup
Pass tracks directly to AudioPlayer for a self-contained widget:
import { AudioPlayer, AudioPlayerControlBar, AudioPlayerPlay } from "@/components/player";
<AudioPlayer tracks={myTracks}>
<AudioPlayerControlBar>
<AudioPlayerPlay />
</AudioPlayerControlBar>
</AudioPlayer>For shared state across multiple players or app-wide persistence, mount AudioProvider once at the root:
// app/layout.tsx
import { AudioProvider } from "@/components/player";
export default function RootLayout({ children }) {
return (
<html>
<body>
<AudioProvider tracks={initialTracks}>{children}</AudioProvider>
</body>
</html>
);
}tracks vs AudioProvider: Use tracks on AudioPlayer for self-contained widgets. Use AudioProvider at the root when multiple components share the same playback session.
Player
Compact
import {
AudioPlayer,
AudioPlayerControlBar,With queue
import {
AudioPlayer,
AudioPlayerControlBar,Variants
import {
AudioPlayer,
AudioPlayerControlBar,Sizes
import {
AudioPlayer,
AudioPlayerControlBar,AudioPlayer
Container for all player controls.
| Prop | Type | Default | Description |
|---|---|---|---|
tracks | Track[] | - | When provided, wraps children with AudioProvider automatically. |
variant | "default" | "ghost" | "default" | Visual style. ghost is transparent with a hover background. |
size | "sm" | "default" | "default" | Controls padding and border radius. |
className | string | - | Additional CSS classes. |
Inherits all other props from HTMLDivElement. The underlying CVA definition is exported as audioPlayerVariants for extension.
AudioProvider
Connects the HTML audio element to the Zustand store. Handles event listeners, retries, preloading, and state restoration.
| Prop | Type | Default | Description |
|---|---|---|---|
tracks | Track[] | [] | Initial tracks to populate the queue. |
children | ReactNode | - | Components that share this audio session. |
AudioPlayerButton
Shared button primitive used by all player controls. Wraps a Button with an optional tooltip.
| Prop | Type | Default | Description |
|---|---|---|---|
tooltipLabel | string | - | When provided, wraps the button in a tooltip. |
Inherits all other props from Button.
AudioPlayerControlBar
Groups controls in a single row or stacked column layout.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "compact" | "stacked" | "compact" | Controls the layout. |
AudioPlayerControlGroup
Flexible row wrapper for arranging control clusters. Use className to adjust alignment.
AudioPlayerPlay
Play/pause button. Shows a spinner during loading/buffering. Spacebar shortcut is enabled automatically.
Inherits all props from AudioPlayerButton.
AudioPlayerSkipBack / AudioPlayerSkipForward
Navigate between tracks.
Inherits all props from AudioPlayerButton.
AudioPlayerRewind / AudioPlayerFastForward
Seek backward or forward by 10 seconds. Disabled for live streams.
Inherits all props from AudioPlayerButton.
AudioPlayerSeekBar
Seek timeline showing playback and buffered progress. Locked to 100% for live streams.
Inherits all props from Transport (except value, onSeek, bufferedValue).
AudioPlayerTimeDisplay
Displays current time or remaining time. Shows a live indicator for streams.
| Prop | Type | Default | Description |
|---|---|---|---|
remaining | boolean | false | Show remaining time instead of elapsed time. |
AudioPlayerVolume
Dropdown with a horizontal fader to control volume and mute.
Inherits all props from Fader (except value, onValueChange, min, max, orientation, size).
Tracks
AudioTrackList renders a list of tracks. Omit tracks to read from the global queue; pass tracks for controlled mode.
Single track
"use client";
import {Default
"use client";
import { toast } from "sonner";
import { AudioTrackList } from "@/components/audio/player";Grid
"use client";
import { toast } from "sonner";
import { AudioTrackList } from "@/components/audio/player";Sortable
"use client";
import { toast } from "sonner";
import { AudioTrackList } from "@/components/audio/player";Sortable Grid
"use client";
import { toast } from "sonner";
import { AudioTrackList } from "@/components/audio/player";AudioTrack
Renders a single track row. media and actions are composed, not configured — pass the pieces you want.
| Prop | Type | Default | Description |
|---|---|---|---|
trackId | string | number | - | Look up a track from the queue by id (store mode). |
track | Track | - | Render a provided track object (controlled mode). |
index | number | - | Display index, exposed to AudioTrackIndex. |
onClick | () => void | - | Called when the row is clicked. |
onRemove | (trackId: string) => void | - | Enables AudioTrackRemoveAction when provided. |
media | React.ReactNode | - | Left-side content, e.g. <AudioTrackCover />. |
actions | React.ReactNode | - | Right-side content, e.g. <AudioTrackPlayPauseAction />. |
<AudioTrack
trackId={track.id}
media={<AudioTrackCover />}
actions={<AudioTrackPlayPauseAction />}
/>
// Sortable row with remove support
<AudioTrack
trackId={track.id}
media={
<>
<SortableDragHandle />
<AudioTrackCover />
</>
}
actions={
<>
<AudioTrackRemoveAction />
<AudioTrackPlayPauseAction />
</>
}
onRemove={handleRemove}
/>AudioTrackCover, AudioTrackIndex, AudioTrackPlayPauseAction, and AudioTrackRemoveAction read track state from context — they only work inside AudioTrack. AudioTrackRemoveAction renders nothing for the currently playing track or when onRemove isn't set.
Mode constraint: Use either trackId or track, not both. trackId requires an AudioProvider in the tree.
AudioTrackList
| Prop | Type | Default | Description |
|---|---|---|---|
tracks | Track[] | - | Controlled list. Omit to read from the global queue. |
onTrackSelect | (index: number, track?: Track) => void | - | Called when a track is selected. |
onTrackRemove | (trackId: string) => void | - | Called when a track is removed. Enables remove actions automatically. |
mode | "static" | "sortable" | "static" | Enable drag-and-drop reordering. |
media | "cover" | "index" | "cover" | Media style. In sortable mode a drag handle is added automatically. |
actions | "none" | "play-pause" | "remove" | "play-pause-with-remove" | Auto | Action variant per row. Auto: "play-pause-with-remove" when onTrackRemove is set. |
variant | "default" | "grid" | "default" | Stacked list or responsive grid. |
filterQuery | string | - | Text filter (matches title or artist). |
filterFn | (track: Track) => boolean | - | Custom filter. Overrides filterQuery when both are set. |
emptyLabel | string | "No tracks found" | Empty state label. |
emptyDescription | string | "Try adding some tracks" | Empty state description. |
Sortable constraint: Drag-and-drop reordering only updates the store when the list is unfiltered and in store mode.
Queue
All queue controls work together or independently.
Simple
"use client";
import {All controls
import {
AudioPlayer,
AudioPlayerControlBar,Shuffle and repeat
import {
AudioPlayer,
AudioPlayerControlBar,Preferences
import {
AudioPlayer,
AudioPlayerControlBar,AudioQueue
A dialog with the full queue: search, selection, remove, and drag-and-drop reordering.
| Prop | Type | Default | Description |
|---|---|---|---|
onTrackSelect | (index: number) => void | - | Called when a track is selected from the queue. |
searchPlaceholder | string | "Search for a track..." | Search input placeholder. |
emptyLabel | string | "No tracks found" | Empty state label. |
emptyDescription | string | "Try searching for a different track" | Empty state description. |
Search and reorder: Drag-and-drop is disabled while a search filter is active.
AudioQueueShuffle
Toggle that enables/disables shuffle. Persisted to localStorage.
Inherits all props from Toggle (except onPressedChange).
AudioQueueRepeatMode
Toggle that cycles through repeat modes: none → all → one. Persisted to localStorage.
Inherits all props from Toggle.
AudioQueuePreferences
Dropdown combining repeat mode and insert mode (first, last, after current) in one compact menu.
Inherits all props from AudioPlayerButton.
Playback Speed
"use client";
import {AudioPlaybackSpeed
Dropdown to change playback speed. Disabled automatically for live streams.
| Prop | Type | Default | Description |
|---|---|---|---|
speeds | readonly { value: number; label: string }[] | PLAYBACK_SPEEDS | Speed options. Default: 0.5×, 0.75×, 1×, 1.25×, 1.5×, 2×. |
size | ButtonSize | - | "icon" hides the gauge icon, shows only the label. |
variant | ButtonVariant | "outline" | Button variant. |
Notes
Live streams: Seeking, rewind, fast-forward, and playback speed are disabled automatically. The seek bar locks to 100%.
Spacebar shortcut: AudioPlayerPlay registers a global keydown listener for Space when the document body is focused.
More Shadcn Player components
Browse 7 production-ready audio/ui Player components for players, mixers, and synth interfaces. These examples use Base UI primitives from @base-ui/react and stay fully compatible with Shadcn Create so radius, color, and typography match your configured theme.
Browse all 7 Shadcn Player components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the audio/ui library.