Building a Composable Audio Player: My Journey in Web Audio Development

My Story

I'm a developer passionate about audio and the web. During the week, I code. On weekends, I produce music. These two worlds remained separate for me for a long time, until the day I decided to bring them together.

The Spark

It all started when I wanted to share my music with my loved ones. I was producing tracks in my home studio, but sharing was always complicated. Existing platforms didn't really meet my needs. I wanted something that could:

  • Showcase my music
  • Be simple for non-technical people
  • Stay personal and authentic
  • Work perfectly on all devices

From Ouest Audio to audio/ui

I started building Ouest Audio, a complete music streaming application.

The Evolution

Ouest Audio became a complex application with features like:

  • Playlists and queue management
  • Next/previous track controls
  • Shuffle playback
  • Multiple audio sources

While these features are excellent for a complete streaming app, I realized that many developers mainly needed a solid foundation for audio playback. That's when I decided to extract the core audio functionality into a separate, composable component registry — audio/ui.

User Feedback That Shaped audio/ui

I shared early versions with my musician friends, and their feedback was invaluable:

  • "The player is heavy on mobile"
  • "Why can't I easily share a specific track?"
  • "I'd like to customize the player for my own music"
  • "I need to manage my playlists"

The Composable Approach

Rather than building yet another monolithic audio player, I focused on something more flexible. My goal was to make audio development as simple as assembling React components, while leaving the freedom to:

  • Choose only what you need
  • Customize every piece
  • Own your code
  • Build your way

In the philosophy of shadcn, audio/ui is a component registry designed to be copied into your project rather than installed as a dependency. This approach gives you total control over the code and style, making customization and maintenance easier.

Breaking Down the Components

Here's how I built each piece.

The Complete Player

Available Components

The player above is composed of several components that work together:

Playback Controls

  • AudioPlayerPlay: Play/pause with keyboard shortcut (spacebar)
  • AudioPlayerSkipBack / AudioPlayerSkipForward: Navigation between tracks
  • AudioPlayerRewind / AudioPlayerFastForward: Rewind/forward by 10 seconds

Progress Bar

  • AudioPlayerSeekBar: Progress bar with buffer support
  • AudioPlayerTimeDisplay: Display current or remaining time
  • Smooth drag-and-drop and real-time updates

Queue Management

  • AudioTrackList: Track list with search, sort, and drag-and-drop
  • AudioQueue: Queue management dialog with search
  • AudioQueueShuffle / AudioQueueRepeatMode: Shuffle and repeat playback controls
  • AudioQueuePreferences: Compact menu with all queue settings

Volume

  • AudioPlayerVolume: Volume control with dropdown menu
  • Quick mute toggle and visual feedback

Installation and Usage

To add audio/ui components to your project, simply use the Shadcn CLI:

pnpm dlx shadcn@latest add @audio/player

This command will automatically copy the component source code and its dependencies into your project.

AudioProvider Configuration

The AudioProvider initializes the audio element, handles playback events, retries on error, preloads next tracks, and synchronizes audio state with the Zustand store.

Wrap your application with AudioProvider at the root level:

import { AudioProvider } from "@/components/audio/provider";
 
export default function RootLayout({ children }) {
  return (
    <AudioProvider tracks={initialTracks}>{children}</AudioProvider>
  );
}

Basic Usage

import {
  AudioPlayer,
  AudioPlayerControlBar,
  AudioPlayerPlay,
} from "@/components/audio/player";
 
export function MyAudioPlayer() {
  return (
    <AudioPlayer>
      <AudioPlayerControlBar>
        <AudioPlayerPlay />
      </AudioPlayerControlBar>
    </AudioPlayer>
  );
}

Complete Player with Queue

Here's an example of a complete player with all features:

Customization

Since the code is copied directly into your project, you can freely modify the source files according to your needs. Adapt styles, change behavior, or extend functionality.

Key Features

Queue Management

audio/ui includes a complete queue management system:

  • Queue: Add, remove, and reorganize tracks
  • Search: Filter tracks by title or artist
  • Sort: Reorganize by drag-and-drop
  • Insertion Modes: Choose where to add (beginning, end, after current track)

Playback Modes

  • Shuffle: Shuffle the queue
  • Repeat: Three modes available (none, one track, entire queue)
  • Navigation: Next/previous track controls with smart logic

Store and State

The system uses Zustand with automatic localStorage persistence for playback state, queue, history, and user preferences.

Lessons Learned

Technical Points

  • The Web Audio API is powerful but complex
  • Browser compatibility is an ongoing battle
  • Zustand proved to be an excellent choice for state management
  • Performance optimization requires granular selectors

Common Challenges

  • Resources must be properly cleaned up
  • Browser autoplay policies are strict
  • Audio context can be suspended
  • Error states must be properly handled
  • Queue management with shuffle and repeat requires complex logic

Best Practices

  • Keep an API simple and intuitive
  • TypeScript is your ally
  • Error handling is essential
  • Mobile-first is the way to go
  • Accessibility is not optional

What's Next

This project was an opportunity to bring together my two passions: music and development. Over the past two years, I've spent more time coding than producing music, but the lessons learned from both worlds have been invaluable.

Current State of audio/ui

audio/ui is now a complete component registry that includes:

  • Audio Player: Composable audio player with all controls
  • Audio Queue: Complete queue management system with search and sort
  • Audio Track: Track display and management components
  • Audio Store: Zustand store with localStorage persistence
  • Audio Library: Singleton $audio for playback management
  • Extended UI Components: Slider with buffer, Sortable List, etc.

What's Coming

I continue to improve and extend audio/ui with additional audio components, advanced features, audio visualizations (waveforms, spectrum analyzers), and enriched documentation.

Resources

Building a Composable Audio Player: My Journey in Web Audio Development - Lucien Loua - UX/UI Developer