Now playingPro

Grow a mini player into the full player in one continuous morph.

Live · keyboard ready

Undertow by Hollis Reed, paused

A wave breaking in amber light, seen from above
  • Media that keeps playing while people browse, such as music, podcasts, or audio lessons.
  • A mini player bar that expands into a full player with artwork and a scrubber.
  • Use bottom-sheet or dialog for a one-off overlay that is not a player.
  • Use voice-recorder for recording and playing back short voice notes.
  • Use slider for a plain seek bar without the player chrome.

Installation

Pro source and install commands unlock with a Pro plan.

example.tsx
import { NowPlaying } from "@/registry/components/now-playing/now-playing"; export function Player() {  return (    <NowPlaying      tracks={[        { id: "1", title: "Night Drive", artist: "Arc Ensemble", duration: 212, artwork: "/covers/night-drive.jpg" },        { id: "2", title: "Low Tide", artist: "Harbor", duration: 185, artwork: "/covers/low-tide.jpg" },      ]}      onPlayingChange={playing => (playing ? audio.play() : audio.pause())}      onIndexChange={index => loadTrack(index)}    />  );}

API reference

2 parts. The first is the root.

NowPlaying

A compact player that grows from a mini bar into a full player in one continuous morph, with a waveform scrubber and artwork that slides in the direction you skip.

PropTypeDefaultDescription
tracksRequired{ id: string; title: string; artist: string; duration: number; artwork: string; artworkAlt?: string }[]–The queue. duration is in seconds.
indexnumber–Controlled position in the queue.
defaultIndexnumber0Initial position when uncontrolled.
onIndexChange(index: number) => void–Called when the track changes by skip or when a track ends. The queue wraps at both ends.
playingboolean–Controlled playback state.
defaultPlayingbooleanfalseInitial playback state when uncontrolled.
onPlayingChange(playing: boolean) => void–Called on play and pause.
defaultExpandedbooleanfalseStarts as the full player.
labelstring"Now playing"Accessible name of the player section.
classNamestring–Extra class on the root.

NowPlayingLevels

Three small level bars that dance while a track plays and rest while paused.

PropTypeDefaultDescription
playingRequiredboolean–Bars move only while true.
classNamestring–Extra class on the bars.
EnterorSpace
Expands or collapses the player and activates play, pause, and skip.
ArrowLeftorArrowRightorArrowUporArrowDown
On the waveform, seeks 5 seconds back or forward.
PageUporPageDown
On the waveform, seeks 30 seconds.
HomeorEnd
On the waveform, jumps to the start or end.
Escape
Collapses the full player.
  • The waveform is a slider with aria-valuetext such as "1:05 of 3:32".
  • Expand and collapse buttons report aria-expanded. Focus moves to the collapse button on open and back to the mini bar on close.
  • Previous restarts the current track when more than 3 seconds have played, and skips back otherwise.
  • The current track and play state are announced in a polite live region; artwork is decorative unless artworkAlt is set.
  • The mini bar morphs into the full player with shared layout while the shell height springs to fit. In the full player, pulling the artwork down more than 70px or flicking it closes the player; an upward pull rubber-bands.
  • Artwork slides and blurs in the direction you skip; the waveform stretches under a scrub and level bars dance while playing.
  • MotionConfig follows the user's reduced motion setting, replacing travel with short fades; the level bars hold still.
  • The shell is min(100%, 21rem) wide; below 360px viewport width the mini bar hides the next button to fit.
  • The expanded artwork uses touch-action none for the pull-down gesture, while the waveform keeps pan-y so the page still scrolls.
  • Playback is an internal useAnimationFrame clock that ticks every frame; it returns early while paused but the frame callback stays registered.
  • The waveform is 54 bars and one ResizeObserver; wire a real audio element through the callbacks rather than the internal clock for long sessions.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Choose it for media that keeps playing while people browse. For a one-off overlay use bottom-sheet or dialog.
  • Playback runs on an internal clock, so it works without audio; wire onPlayingChange and onIndexChange to a real audio element when needed.

The full library index for assistants is at /llms.txt.