React voice recorder component and hook with waveform visualization
npm install react-voice-recorder-kit
bash
npm install react-voice-recorder-kit
or
pnpm add react-voice-recorder-kit
or
yarn add react-voice-recorder-kit
`
Requires React 18+
---
Quick Start (Using Component)
`tsx
'use client'
import { useState } from 'react'
import { VoiceRecorder } from 'react-voice-recorder-kit'
export default function Page() {
const [file, setFile] = useState(null)
const [url, setUrl] = useState(null)
return (
React Voice Recorder Kit
autoStart={false}
onStop={(audioFile, audioUrl) => {
setFile(audioFile)
setUrl(audioUrl)
}}
onDelete={() => {
setFile(null)
setUrl(null)
}}
/>
{url && (
{file && (
File name: {file.name} | Size: {file.size} bytes
)}
)}
)
}
`
---
Usage in Next.js (App Router)
`tsx
'use client'
import { VoiceRecorder } from 'react-voice-recorder-kit'
export default function VoicePage() {
return (
)
}
`
---
Component API
$3
| Prop | Type | Default | Description |
| --------- | --------------------------------- | --------- | ---------------------------------------------- |
| autoStart | boolean | true | Auto-start recording on mount |
| onStop | (file: File, url: string) => void | undefined | Callback after recording stops |
| onDelete | () => void | undefined | Callback after recording is deleted |
| width | string \| number | '100%' | Component width |
| height | string \| number | undefined | Component height |
| style | CSSProperties | undefined | Additional styles for container |
$3
| Prop | Type | Default | Description |
| --------------------------- | --------------------------------------- | ------------------------------------------------------------ | ------------------------------------ |
| backgroundColor | string | '#ffffff' | Background color |
| borderColor | string | '#e5e7eb' | Border color |
| borderRadius | string \| number | 4 | Border radius |
| padding | string \| number | '6px 10px' | Internal padding |
| gap | string \| number | 8 | Gap between elements |
| recordingIndicatorColor | string | '#ef4444' | Recording indicator color |
| idleIndicatorColor | string | '#9ca3af' | Idle indicator color |
| timeTextColor | string | undefined | Time text color |
| timeFontSize | string \| number | 12 | Time font size |
| timeFontWeight | string \| number | 500 | Time font weight |
| timeFontFamily | string | 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif' | Time font family |
| visualizerBarColor | string \| (level: number, index: number) => string | '#4b5563' | Waveform bar color |
| visualizerBarWidth | number | 3 | Waveform bar width |
| visualizerBarGap | number | 4 | Gap between bars |
| visualizerBarHeight | number | 40 | Waveform bar height |
| visualizerHeight | number | 40 | Total waveform height |
| buttonSize | number | 28 | Button size |
| buttonBackgroundColor | string | '#ffffff' | Button background color |
| buttonBorderColor | string | '#e5e7eb' | Button border color |
| buttonBorderRadius | string \| number | 999 | Button border radius |
| buttonHoverBackgroundColor | string | undefined | Button hover background color |
| buttonGap | number | 4 | Gap between buttons |
| errorTextColor | string | '#dc2626' | Error text color |
| errorFontSize | string \| number | 10 | Error font size |
| errorFontFamily | string | 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif' | Error font family |
| iconSize | number | 18 | Icon size |
| iconColor | string | undefined | Icon color |
$3
| Prop | Type | Default | Description |
| --------------- | --------- | --------- | ------------------------ |
| customPlayIcon | ReactNode | undefined | Custom play icon |
| customPauseIcon | ReactNode | undefined | Custom pause icon |
| customStopIcon | ReactNode | undefined | Custom stop icon |
| customResumeIcon| ReactNode | undefined | Custom resume icon |
| customDeleteIcon| ReactNode | undefined | Custom delete icon |
| customRepeatIcon| ReactNode | undefined | Custom repeat icon |
---
Component Usage Examples
$3
`tsx
import { VoiceRecorder } from 'react-voice-recorder-kit'
function SimpleRecorder() {
return
}
`
$3
`tsx
import { VoiceRecorder } from 'react-voice-recorder-kit'
function CustomStyledRecorder() {
return (
backgroundColor="#f3f4f6"
borderColor="#d1d5db"
borderRadius={12}
recordingIndicatorColor="#10b981"
visualizerBarColor="#6366f1"
buttonBackgroundColor="#ffffff"
buttonHoverBackgroundColor="#f9fafb"
/>
)
}
`
$3
`tsx
import { useState } from 'react'
import { VoiceRecorder } from 'react-voice-recorder-kit'
function RecorderWithCallbacks() {
const [audioFile, setAudioFile] = useState(null)
return (
autoStart={false}
onStop={(file, url) => {
console.log('Recording stopped:', file.name)
setAudioFile(file)
}}
onDelete={() => {
console.log('Recording deleted')
setAudioFile(null)
}}
/>
)
}
`
$3
`tsx
import { VoiceRecorder } from 'react-voice-recorder-kit'
function DynamicColorRecorder() {
return (
visualizerBarColor={(level, index) => {
const hue = (level * 120).toString()
return hsl(${hue}, 70%, 50%)
}}
/>
)
}
`
---
Using the Hook (useVoiceRecorder)
For full control over the UI, you can use the hook directly.
$3
`ts
import { useVoiceRecorder } from 'react-voice-recorder-kit'
`
$3
`ts
type UseVoiceRecorderOptions = {
autoStart?: boolean
onStop?: (file: File, url: string) => void
onDelete?: () => void
}
`
$3
`ts
type UseVoiceRecorderReturn = {
state: RecorderState
isRecording: boolean
isStopped: boolean
isTemporaryStopped: boolean
isPlaying: boolean
isPaused: boolean
seconds: number
levels: number[]
error: string | null
audioUrl: string | null
audioFile: File | null
start: () => void
handlePause: () => void
handleStopTemporary: () => void
handleStop: () => void
handleResume: () => void
handlePreviewPlay: () => void
handlePlay: () => void
handleRestart: () => void
handleDelete: () => void
handleRecordAgain: () => void
}
`
| Property | Type | Description |
| ----------------- | -------------- | ---------------------------------------------- |
| state | RecorderState | Current state: 'idle' \| 'recording' \| 'paused' \| 'reviewing' \| 'playing' |
| isRecording | boolean | Is currently recording |
| isStopped | boolean | Is recording stopped |
| isTemporaryStopped| boolean | Is recording temporarily stopped |
| isPlaying | boolean | Is currently playing |
| isPaused | boolean | Is recording paused |
| seconds | number | Time in seconds |
| levels | number[] | Array of 40 audio levels (0 to 1) |
| error | string \| null | Error message if any |
| audioUrl | string \| null | URL of recorded audio file |
| audioFile | File \| null | Recorded audio file |
| start | () => void | Start recording |
| handlePause | () => void | Pause recording |
| handleStopTemporary| () => void | Temporary stop and review |
| handleStop | () => void | Stop and save recording |
| handleResume | () => void | Resume recording after pause |
| handlePreviewPlay | () => void | Play preview (in paused state) |
| handlePlay | () => void | Play recorded file |
| handleRestart | () => void | Restart recording |
| handleDelete | () => void | Delete recording and return to initial state |
| handleRecordAgain | () => void | Record again (same as handleRestart) |
---
Complete Hook Usage Example
`tsx
'use client'
import { useVoiceRecorder } from 'react-voice-recorder-kit'
export default function CustomRecorder() {
const {
state,
isRecording,
isPaused,
isStopped,
isPlaying,
seconds,
levels,
audioUrl,
audioFile,
error,
start,
handlePause,
handleResume,
handleStop,
handlePlay,
handleDelete,
handleRestart
} = useVoiceRecorder({ autoStart: false })
const formatTime = (secs: number) => {
const minutes = Math.floor(secs / 60)
const sec = secs % 60
return ${minutes}:${sec.toString().padStart(2, '0')}
}
return (
Custom Voice Recorder
Status: {state} | Time: {formatTime(seconds)}
{!isRecording && !isStopped && (
)}
{isRecording && !isPaused && (
<>
>
)}
{isPaused && (
<>
>
)}
{isStopped && audioUrl && (
<>
>
)}
{error && (
{error}
)}
style={{
marginTop: 20,
height: 40,
display: 'flex',
alignItems: 'flex-end',
gap: 4,
overflow: 'hidden'
}}
>
{levels.map((level, index) => {
const height = 5 + level * 35
return (
key={index}
style={{
width: 4,
height,
borderRadius: 4,
background: '#444'
}}
/>
)
})}
{audioUrl && (
)}
---
Recording States (RecorderState)
The component and hook have 5 different states:
- idle: Initial state, ready to start
- recording: Currently recording
- paused: Recording paused (can be resumed)
- reviewing: Recording completed and under review
- playing: Playing recorded file
---
Features
* Voice recording using MediaRecorder API
* Animated audio waveform visualization during recording and playback
* Support for pause and resume
* Support for playing recorded files
* Time display in MM:SS format
* Error handling and error message display
* Ready-to-use UI with control buttons
* Fully customizable styling and sizing
* No external dependencies
* Support for custom icons
* Dynamic color waveforms
---
Important Notes
1. Requires microphone access in the browser
2. Recorded files are saved in WebM format
3. In paused state, you can play a preview of the recording
4. You can dynamically set bar colors using visualizerBarColor`