Voice note

A voice message bar with a scrubbable waveform and a play control.

Dependencies

motion

Interaction Type

Press play to start. The play triangle splits into the pause bars, the waveform fills from the left, and soft lights circle the inside edge of the bar. Pause and they wind down to a stop. Drag across the waveform to scrub, or focus it and use the arrow keys. Press the time to change playback speed.

Props

Options you can pass to customize this component.

Prop
Type
Description
src
string

URL of the audio file to play. Without it the bar runs on a timer, which is what the demo above does.

duration
number

Length of the clip in seconds. Ignored once a real file reports its own duration.

waveform
number[]

Bar heights from 0 to 1. Leave it out and the bars are generated from the seed.

bars
number

How many bars to generate. They share the width evenly, so more bars means thinner bars.

seed
number

Picks which generated waveform you get. The same seed always draws the same bars.

playing
boolean

Drives playback yourself. Leave it out and the bar tracks its own state.

defaultPlaying
boolean

Whether the bar starts playing when you are not driving it.

onPlayingChange
(playing: boolean) => void

Called whenever playback starts or stops.

onEnded
() => void

Called when the clip reaches the end, just after the bar rewinds to the start.

accent
#FC4C01#1A73F2#4ADE80

Any hex color for the light behind the bar. The waveform itself stays neutral.

size
smmdlg

Bar size. Height, control, bar width and text all scale together.

speeds
number[]

Speeds the time label cycles through when pressed. Pass a single speed to pin it and turn the label back into plain text.

onSpeedChange
(speed: number) => void

Called with the new speed each time the label is pressed.

seekable
boolean

Whether the waveform can be scrubbed. The arrow keys move 5 seconds at a time, Home and End jump to the ends. Off removes both the pointer and the keyboard seeking.

className
string

Extra classes merged onto the root element (data-slot="voice-note"). Set the width here.

children
ReactNode

On VoiceNoteGroup only. Wrap several bars in it and starting one stops the rest, the way a chat thread behaves.

Installation

npx shadcn@latest add swamimalode07/rare-ui/voice-note

How to use

"use client"
import { VoiceNote } from "@/components/ui/voice-note"
export function Demo() {
return <VoiceNote src="/audio/note.mp3" className="w-[340px]" />
}
// no file yet: pass a length and it runs on a timer
// <VoiceNote duration={53} accent="#2563EB" />
// wrap a thread in VoiceNoteGroup and starting one stops the rest
// <VoiceNoteGroup>
// <VoiceNote src="/audio/first.mp3" />
// <VoiceNote src="/audio/second.mp3" />
// </VoiceNoteGroup>

Source Code

Click the code icon in the top-right corner to view the source code.

Keep in mind

Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.

Contact

Found a bug or issue? Feel free to drop a DM.

License & Usage

  • •MIT with the Commons Clause and an attribution requirement. Free to use, modify and ship in personal and commercial projects, closed source included. You own the code once it is in your project.
  • •Credit is required. Any project shipping a Rare UI component must credit Rare UI with a visible link back to rareui.com, in a footer, an about page, a credits screen or a README.
  • •Don't strip the credit or the copyright notice from the source you copied.
  • •Don't sell, sublicense or redistribute the components themselves, on their own, bundled into a template, kit, theme or paid course, or ported to another framework.
  • •Don't republish them. No mirrors, no re-uploads, no listing them as your own work.
  • •Don't repackage the registry as a competing component library.
  • •Don't claim authorship of a component or of Rare UI itself.
  • •The LICENSE file in the repository is the full text and governs. Ask first if your use doesn't fit these rules.
Voice note