A powerful React SDK for screen recording with camera and audio support
Features • Installation • Quick Start • API Reference • Examples
Click the image above to watch RecordPanel in action - screen recording with camera and audio support
RecordPanel is a feature-rich React SDK that enables screen recording with camera and audio capture capabilities. It provides a beautiful, draggable floating UI with real-time audio feedback, making it perfect for creating video tutorials, bug reports, or any application that requires screen recording functionality.
✨ Core Features
- 🎥 Screen Recording - Capture your entire screen or specific windows
- 📹 Camera Support - Include your webcam feed with circular preview (Loom-style)
- 🎤 Audio Capture - Record microphone and system audio simultaneously
- 🎨 Beautiful UI - Modern, draggable floating panel with smooth animations
- 📊 Audio Feedback - Real-time visual audio level indicators
- ⏸️ Pause/Resume - Control recording playback on the fly
- 🔄 Restart - Quickly restart recordings without re-requesting permissions
- ⏱️ Duration Display - Real-time recording duration in MM:SS format
- 🎯 Simple API - One-line
capture()method for quick integration
🎨 UI Features
- Draggable floating panel (drag anywhere except buttons)
- Circular camera preview (120px, Loom-style)
- Compact, modern design
- Real-time audio level visualization
- Recording indicator with pulsing red dot
- Configurable theme (light, dark, auto)
- Customizable stop button text
🔧 Technical Features
- TypeScript support with full type definitions
- Tree-shakeable (only imports what you use)
- Zero CSS conflicts (scoped styles)
- Browser permission management
- Automatic codec fallback (VP9 → VP8 → MP4)
- Memory-efficient blob handling
- Pause/resume duration tracking
npm install recordpanelor
yarn add recordpanelor
pnpm add recordpanelRecordPanel requires React 18+ or React 19+:
npm install react react-domWrap your application with RecordPanelHost at the root level:
import { RecordPanelHost } from 'recordpanel'
import 'recordpanel/styles'
function App() {
return (
<RecordPanelHost>
<YourApp />
</RecordPanelHost>
)
}Use the useRecordPanel hook in any component:
import { useRecordPanel } from 'recordpanel'
function MyComponent() {
const recorder = useRecordPanel()
const handleRecord = async () => {
// Simple one-line API
const result = await recorder.capture({
cameraEnabled: true,
audioEnabled: true
})
console.log('Recording:', result)
// result contains: { blob, url, mimeType, size }
}
return <button onClick={handleRecord}>Start Recording</button>
}import { useState } from 'react'
import { RecordPanelHost, useRecordPanel } from 'recordpanel'
import 'recordpanel/styles'
function RecordingComponent() {
const [recording, setRecording] = useState(null)
const recorder = useRecordPanel()
const handleCapture = async () => {
try {
const result = await recorder.capture({
cameraEnabled: true,
audioEnabled: true
})
setRecording(result)
// Download the recording
const a = document.createElement('a')
a.href = result.url
a.download = `recording-${Date.now()}.webm`
a.click()
// Clean up
URL.revokeObjectURL(result.url)
} catch (error) {
console.error('Recording failed:', error)
}
}
return (
<div>
<button onClick={handleCapture}>Record Screen</button>
{recording && (
<video src={recording.url} controls />
)}
</div>
)
}
function App() {
return (
<RecordPanelHost>
<RecordingComponent />
</RecordPanelHost>
)
}The root component that provides the recording context to your app.
interface RecordPanelHostProps {
children: ReactNode
config?: RecorderConfig
}interface RecorderConfig {
theme?: 'light' | 'dark' | 'auto' // Default: 'auto'
stopButtonText?: string // Default: 'Send'
}Example:
<RecordPanelHost
config={{
theme: 'dark',
stopButtonText: 'Finish'
}}
>
<YourApp />
</RecordPanelHost>Returns the recorder API object. Must be used within a component wrapped by RecordPanelHost.
const recorder = useRecordPanel()The simplest way to record. Starts recording, shows UI, waits for user to stop, and returns the result.
const result = await recorder.capture({
cameraEnabled?: boolean // Default: true
audioEnabled?: boolean // Default: true
})
// Returns: RecordingResultExample:
const handleCapture = async () => {
try {
const result = await recorder.capture({
cameraEnabled: true,
audioEnabled: true
})
console.log('Recording complete:', result)
} catch (error) {
console.error('Capture failed:', error)
}
}Starts recording. Requests permissions if not already granted.
await recorder.start({
cameraEnabled?: boolean // Default: true
audioEnabled?: boolean // Default: true
})Stops recording and returns the result.
const result = await recorder.stop()
// Returns: RecordingResult | nullPauses the current recording.
recorder.pause()Resumes a paused recording.
recorder.resume()Stops the current recording and starts a new one. Preserves permissions if already granted.
await recorder.restart()Shows the recorder UI overlay.
recorder.show()Hides the recorder UI overlay.
recorder.hide()Updates the recorder configuration dynamically.
recorder.setConfig({
theme: 'dark',
stopButtonText: 'Finish'
})Returns the current recording state.
const state = recorder.getState()
// Returns: 'idle' | 'requesting' | 'recording' | 'paused' | 'stopped'Checks if currently recording.
const isRecording = recorder.isRecording() // booleanChecks if recording is paused.
const isPaused = recorder.isPaused() // booleanChecks if the UI overlay is visible.
const isVisible = recorder.isVisible() // booleanGets the current recording duration in seconds (includes pause time handling).
const duration = recorder.getRecordingDuration() // number (seconds)interface RecordingResult {
blob: Blob // The recording blob
url: string // Object URL (revoke after use)
mimeType: string // e.g., 'video/webm' or 'video/mp4'
size: number // Size in bytes
}type RecorderState = 'idle' | 'requesting' | 'recording' | 'paused' | 'stopped'interface RecorderConfig {
theme?: 'light' | 'dark' | 'auto'
stopButtonText?: string
}function SimpleRecording() {
const recorder = useRecordPanel()
const handleRecord = async () => {
const result = await recorder.capture()
console.log('Recording:', result)
}
return <button onClick={handleRecord}>Record</button>
}function AdvancedRecording() {
const recorder = useRecordPanel()
const [isRecording, setIsRecording] = useState(false)
const handleStart = async () => {
await recorder.start({
cameraEnabled: true,
audioEnabled: true
})
setIsRecording(true)
}
const handleStop = async () => {
const result = await recorder.stop()
if (result) {
console.log('Recording:', result)
setIsRecording(false)
}
}
const handlePause = () => {
recorder.pause()
}
const handleResume = () => {
recorder.resume()
}
return (
<div>
{!isRecording ? (
<button onClick={handleStart}>Start Recording</button>
) : (
<>
<button onClick={handlePause}>Pause</button>
<button onClick={handleResume}>Resume</button>
<button onClick={handleStop}>Stop</button>
</>
)}
</div>
)
}function RecordingWithState() {
const recorder = useRecordPanel()
const [recording, setRecording] = useState(null)
const [duration, setDuration] = useState(0)
useEffect(() => {
if (recorder.isRecording()) {
const interval = setInterval(() => {
setDuration(recorder.getRecordingDuration())
}, 1000)
return () => clearInterval(interval)
}
}, [recorder.isRecording()])
const handleCapture = async () => {
const result = await recorder.capture()
setRecording(result)
}
return (
<div>
<button onClick={handleCapture}>Record</button>
{recorder.isRecording() && (
<div>Recording: {Math.floor(duration / 60)}:{(duration % 60).toFixed(0).padStart(2, '0')}</div>
)}
{recording && (
<video src={recording.url} controls />
)}
</div>
)
}function ThemedApp() {
return (
<RecordPanelHost
config={{
theme: 'dark',
stopButtonText: 'Finish Recording'
}}
>
<YourApp />
</RecordPanelHost>
)
}The RecordPanel UI provides a comprehensive set of controls:
- Draggable - Click and drag anywhere on the panel (except buttons) to reposition
- Compact Design - Small footprint, doesn't obstruct your screen
- Smooth Animations - Slide-in animation when appearing
- Circular Design - 120px circular preview (Loom-style)
- Positioned Above Controls - Appears above the control bar when enabled
- Recording Indicator - Red pulsing dot in the top-right corner
- Audio Feedback - Visual audio level bar at the bottom
- Duration Display - Shows recording time in MM:SS format
- Audio Meter - Real-time audio level visualization (5 bars)
- Camera Toggle - Enable/disable camera feed
- Audio Toggle - Enable/disable microphone
- Pause/Resume - Control recording playback
- Restart - Restart recording (preserves permissions)
- Stop/Send - Stop recording and get result (configurable text)
- Close - Hide the UI overlay
RecordPanel uses CSS variables that you can customize:
:root {
--recordpanel-primary: 221 83 53;
--recordpanel-primary-foreground: 0 0 100;
--recordpanel-border: 214 218 222;
--recordpanel-muted: 248 249 250;
/* ... more variables */
}<RecordPanelHost
config={{
theme: 'auto', // 'light' | 'dark' | 'auto'
stopButtonText: 'Send'
}}
>
<YourApp />
</RecordPanelHost>The auto theme automatically follows the system preference.
All RecordPanel styles are scoped with the .recordpanel-* prefix to avoid conflicts. You can override styles if needed:
.recordpanel-overlay {
/* Your custom styles */
}RecordPanel works in all modern browsers that support:
- MediaRecorder API - Chrome 47+, Firefox 25+, Safari 14.1+, Edge 79+
- getDisplayMedia - Chrome 72+, Firefox 66+, Safari 13+, Edge 79+
- getUserMedia - Chrome 53+, Firefox 36+, Safari 11+, Edge 12+
System audio capture is supported in:
- ✅ Chrome/Edge (Windows, macOS, Linux)
- ❌ Firefox (not supported)
- ❌ Safari (not supported)
For the best experience, use:
- Chrome/Edge (full feature support)
- Firefox (screen + microphone only)
- Safari (screen + microphone only)
RecordPanel is written in TypeScript and provides full type definitions:
import {
RecordPanelHost,
useRecordPanel,
type RecordingResult,
type RecorderConfig,
type RecorderState
} from 'recordpanel'If permissions aren't being requested, ensure:
- You're using HTTPS (or localhost)
- The browser supports the required APIs
- No browser extensions are blocking permissions
If recordings are shorter than expected:
- Check browser console for errors
- Ensure sufficient disk space
- Check if browser is closing the MediaRecorder
- Verify microphone permissions are granted
- Check browser audio settings
- System audio requires Chrome/Edge on desktop
- Ensure
RecordPanelHostwraps your app - Check that
recorder.show()is called - Verify CSS is imported:
import 'recordpanel/styles'
Always revoke object URLs after use:
const result = await recorder.capture()
// Use result.url
URL.revokeObjectURL(result.url) // Important!npm run build:libThis creates a library build in the dist folder.
npm run devsrc/
recordpanel/
├── index.ts # Main exports
├── RecorderHost.tsx # Host component
├── RecorderContext.tsx # Context & hook
├── RecorderUI.tsx # UI component
├── recorder.ts # Core recording logic
└── styles.css # Scoped styles
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see LICENSE file for details.
- Built with React
- Icons from Lucide React
- UI components inspired by shadcn/ui
Made with ❤️ by GeekyAnts
