Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Media

Audio Player

Media

Audio Player React component for Tailwind CSS v4

ToolbarCarousel
Live props
Content
title
subtitle
Appearance
variant
tone
color
size
radius
barCountFit
barWidth3px
barGap2px
barRadius2px
waveformHeightAuto
Behavior
decodePeaks
skipSeconds15s
showVolume
downloadable
fileName
exclusive
mediaSession
preload
loop
locale
Code
import { AudioPlayer } from "@/components/ui/audio-player"

<AudioPlayer />
  1. Home
  2. Components
  3. Media
  4. Audio Player
Pro

Audio Player React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React audio player with a waveform you can see and scrub, as a podcast card, a chat voice message or a thin call-log bar.

Press play: the icon turns into pause on a quick spring, the played bars fill in the tone as the recording runs and the time counts up. Tap or click anywhere on the waveform to jump there; drag along it to scrub (the bars and the time follow the finger, the audio seeks on release, and every 120ms with a mouse so you hear where you are). With a mouse, hovering shows a cursor line with the time above it. The card has skip back / forward buttons (15 seconds), a speed menu (a bottom sheet on phones), a volume button with a slider (hidden on touch screens, where the hardware keys do it) and an optional download. The compact voice-message player cycles 1×, 1,5×, 2× on each tap of its chip and shows the length until it starts, then the position. Starting one player pauses the others. While playing, the phone's lock screen and headphone buttons control it. Keyboard: Tab reaches the play button, the waveform and each control; on the waveform Left / Right (or Up / Down) seek 5 s, PageUp / PageDown 30 s, Home / End jump to the start or end, Space, k or Enter play and pause; anywhere in the player Space / k play, j / l seek 10 s, m mutes, Up / Down change the volume, 0 to 9 jump to 0% to 90%, < and > change the speed. A missing file shows a message with a retry. The file also exports Waveform (the bars alone for custom layouts: peaks, progress as a number or a motion value, barCount / barWidth / barGap / barRadius / height, tone / color, onSeek(fraction) makes it a slider with click, drag and arrow keys, onScrub(fraction | null), formatBubble(fraction) for the hover bubble, peaksKey to fade in new bars), computePeaks(buffer, count) (max absolute sample per bucket, normalized 0 to 1), decodePeaks(src, count, { signal }) (fetch, decodeAudioData and computePeaks, cached per src and count) and placeholderPeaks(seed, count) (stable speech-like bars, the same on the server and the client).

Audio Player is a Pro React component in the React media components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add audio-player, together with Button, Dropdown Menu, Popover, Slider, Spinner and 8 more and the npm packages motion and lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add audio-player

Audio Player is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import AudioPlayer from @/components/ui/audio-player.

import { AudioPlayer } from "@/components/ui/audio-player"

export function Episode() {
  return (
    <AudioPlayer
      src="/demo/podcast.mp3"
      title="Sales tax for small businesses"
      subtitle="Summit Podcast · Ep. 12 · Sep 24, 2026"
      cover="/demo/mountains.jpg"
      downloadable
      labels={{ download: "Save episode" }}
    />
  )
}

export function VoiceNote() {
  return <AudioPlayer variant="compact" src="/demo/voice-message.mp3" labels={{ play: "Listen", pause: "Stop" }} />
}

Props

  • src*
    string

    The audio file url. Decoding peaks needs the file on the same origin or served with CORS.

  • titledefault ""
    ReactNode

    The card's title, and the lock-screen title while playing (when it is a string).

  • subtitledefault ""
    ReactNode

    A muted line under the title (show, author, date); the lock-screen artist while playing.

  • cover
    string

    Square artwork url for the card. It sits at 94% while paused and grows to full size while playing. Also the lock-screen artwork.

  • leading
    ReactNode

    Compact only: an avatar or a mic icon before the play button, the chat look.

  • variantdefault "card"
    "card" | "compact" | "minimal"

    card: cover, title, waveform and a controls row on a raised panel. compact: the voice message (play, bars, time, speed chip) for chat bubbles. minimal: play, a thin scrubbable bar and the time for lists and call logs.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    Colors the played bars and the play button. neutral is black in light mode and white in dark mode.

  • colordefault ""
    string

    Any CSS color for the played bars and the play button; replaces the tone. The play icon turns black or white by lightness.

  • sizedefault "md"
    "sm" | "md"

    Button sizes: md has a 40px play button in the card (32px compact and minimal), sm 32px (28px). Every button keeps a 44px touch target.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg"

    Corner radius of the card surface (12 / 16 / 24px) and its cover.

  • barCountdefault 0
    number

    How many bars. 0 fits as many as the width allows (barWidth + barGap each, remeasured on resize); a fixed count spreads over the width.

  • barWidthdefault 3
    number

    Width of each bar in px.

  • barGapdefault 2
    number

    Space between bars in px.

  • barRadiusdefault 2
    number

    Corner radius of each bar in px.

  • waveformHeightdefault 0
    number

    Height of the waveform in px. 0 is automatic: 40px in the card, 28px in the compact player.

  • peaks
    number[]

    Precomputed bar heights from 0 to 1, any length (resampled to the bar count, max per bucket). Skips decoding.

  • decodePeaksdefault true
    boolean

    Without peaks, fetch and decode the file with Web Audio once the player is on screen (one decode per file, cached), fading from placeholder bars to the real waveform. A CORS-blocked file stays on the placeholder bars. The file also exports a decodePeaks(src, count, { signal }) function that returns the same peaks as a Promise<number[]>, for precomputing them yourself.

  • skipSecondsdefault 15
    number

    Seconds for the card's skip back / forward buttons and the lock-screen skip. 0 hides the buttons.

  • rates
    number[]

    Playback speeds. Compact cycles through them on tap (default [1, 1.5, 2]); the card opens a menu (default MEDIA_RATES, 0.5 to 2). One entry hides the speed control.

  • showVolumedefault "auto"
    "auto" | "always" | "never"

    The card's volume button and slider. auto hides it on touch screens, where people use the hardware keys.

  • downloadabledefault false
    boolean

    A download button (card and minimal) that saves the file through file-export's downloadUrl and announces it.

  • fileNamedefault ""
    string

    The downloaded file's name, sanitized, keeping the source's extension. Empty keeps the name from the url.

  • exclusivedefault true
    boolean

    Starting this player pauses every other exclusive player on the page, so two voice notes never talk over each other.

  • mediaSessiondefault true
    boolean

    While playing, sets the lock-screen metadata (title, subtitle, cover) and handles play, pause, seek back / forward and seek-to from the lock screen and headphones.

  • preloaddefault "metadata"
    "none" | "metadata" | "auto"

    The audio element's preload. metadata loads the duration only; none shows --:-- until the first play.

  • loopdefault false
    boolean

    Starts over at the end.

  • localedefault ""
    string

    Formats the speed labels (1.5× in en-US, 1,5× in de-DE). Empty uses UIProvider, then the page language.

  • onPlay
    () => void

    Playback started (passed to useMediaControls).

  • onPause
    () => void

    Playback paused.

  • onEnded
    () => void

    The recording reached its end (the play icon turns into replay).

  • onError
    (error: MediaError | null) => void

    The file could not be loaded or played; the player shows the error row with a retry.

  • onTimeUpdate
    (seconds: number) => void

    Whole seconds while playing and after seeks: resume positions, listening analytics.

  • setApi
    (api: AudioPlayerApi) => void

    The media controls without the ref: playing, second, duration, progress (a motion value), play(), pause(), seek(seconds), seekBy, setRate... Called after mount and again when the state changes (at most once a second while playing), so it can go straight into state.

  • labels
    Partial<AudioPlayerLabels>

    Every string: play "Play", pause "Pause", replay "Replay", loading "Loading", seek "Seek", skipBack(s) "Back {s} seconds", skipForward(s), speed "Speed", cancel "Cancel" (the speed sheet on phones), volume "Volume", mute "Mute", unmute "Unmute", download "Download", downloaded(name), error "The recording could not be played", retry "Try again", live "Live", position(current, total) "{current} of {total}". DEFAULT_AUDIO_PLAYER_LABELS holds the English set.

  • classNames
    Partial<Record<AudioPlayerSlot, string>>

    Classes for the parts: audio, header, cover, meta, title, subtitle, leading, play, waveform, bar, time, controls, skipBack, skipForward, rate, volume, download, error, live.

Parts

  • Waveform

    component

    The bar waveform on its own: draws peaks with a played share, and with onSeek becomes a slider you click, tap, drag or move with the arrow keys. Use it for a custom player layout.

    • peaks*
      readonly number[]

      Bar heights from 0 to 1, any length; resampled to the bar count.

    • progressdefault 0
      number | MotionValue<number>

      The played share from 0 to 1; a motion value moves without re-rendering.

    • barCountdefault 0
      number

      0 fits as many bars as the width allows.

    • barWidthdefault 3
      number

      Bar width in px.

    • barGapdefault 2
      number

      Gap between bars in px.

    • barRadiusdefault 2
      number

      Bar corner radius in px.

    • heightdefault 40
      number

      Height in px.

    • tonedefault "neutral"
      "neutral" | "brand" | "success" | "warning" | "danger" | "info"

      Color of the played bars.

    • color
      string

      Any CSS color for the played bars; replaces the tone.

    • onSeek
      (fraction: number) => void

      Makes the bars a slider: a click or tap seeks, a drag scrubs.

    • onScrub
      (fraction: number | null) => void

      The fraction under the pointer while dragging, then null.

    • seekIntervaldefault 120
      number

      ms between seeks while dragging with a mouse; 0 seeks only on release.

    • formatBubble
      (fraction: number) => string

      The text of the bubble above the cursor, such as 1:12.

    • keyStepdefault 0.05
      number

      Arrow key step as a fraction; PageUp and PageDown move four steps.

    • disableddefault false
      boolean

      Turns off seeking.

    • peaksKeydefault "peaks"
      string | number

      Change it to fade in new bars, from placeholder to decoded peaks.

  • computePeaks

    function

    Turns a decoded AudioBuffer into bar heights: the loudest sample per bucket over the first two channels, normalized so the loudest bar is 1. Signature: (buffer: AudioBuffer, count: number) => number[].

  • placeholderPeaks

    function

    Stable pseudo-random bars from any string (usually the src), shaped like speech with short pauses, shown until the real peaks arrive. Signature: (seed: string, count: number) => number[].

  • DEFAULT_AUDIO_PLAYER_LABELS

    constant

    The English strings of the buttons, the slider and the error state. Spread it to translate a few. Type: AudioPlayerLabels.

  • AudioPlayerApi

    type

    What setApi receives: the useMediaControls result without its ref (playing, duration, second, progress, play(), pause(), toggle(), seek(seconds), seekBy(delta), setRate and the volume controls).

Examples

Voice messages in a chat

Compact players with an avatar. Exclusive: starting one pauses the other. The chip cycles 1×, 1.5×, 2×.

Decoded peaks

No peaks prop: the file is decoded with Web Audio when the card scrolls into view.

Call log

The minimal variant in CRM rows: play, a thin scrubbable bar, the time and a download.

Custom color, dense bars

color="#7C3AED" with barWidth 2 and barGap 1, a taller waveform and a download button.

Error and retry

A missing file shows the message and a retry that reloads the element.

Transcript with setApi

The controls object drives a transcript: the current sentence highlights, a tap seeks there.

Sizes and tones

md and sm buttons for the compact and minimal players, with a tone on the played part.

Dependencies

motionlucide-reactbuttondropdown-menupopoversliderspinnertooltipuse-media-controlsuse-localefile-exportmotionnumber-formattonesui-config

Files

  • components/ui/audio-player.tsx

FAQ

Is the React Audio Player component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Audio Player?

Run npx wingo-ui@latest add audio-player. It also adds the Wingo UI items it builds on (Button, Dropdown Menu, Popover, Slider, Spinner and 8 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/audio-player.

How does Audio Player behave on phones?

The card has skip back / forward buttons (15 seconds), a speed menu (a bottom sheet on phones), a volume button with a slider (hidden on touch screens, where the hardware keys do it) and an optional download.

See also

useMediaControlshookVideo PlayerVoice InputChat MessageFile exportlib

Used in

File SystemInbox Page

More React media components

Excel ViewerDOCX ViewerCSV ViewerDOCX EditorImage compareImage Gallery
All 17 React media components

Articles using this component

  • React Audio Player with Waveform: Scrub, Seek, Peaks

    Component guides · Oct 19, 2026 · 9 min read

  • React Speech to Text Input: Mic, Waveform, Fallback

    Building UI with AI agents · Oct 16, 2026 · 9 min read

PreviousToolbarNext Carousel
Sales tax for small businesses
Summit Podcast · Ep. 12 · Sep 24, 2026
0:00 / --:--

decodePeaks: true · exclusive: true · mediaSession: true · preload: metadata · loop: false · locale: auto