"use client"
import { useEffect, useState } from "react"
import { VoiceButton } from "@/components/ui/voice-button"
export function VoiceButtonDemo() {
const [state, setState] = useState<
"idle" | "recording" | "processing" | "success" | "error"
>("idle")
const handlePress = () => {
if (state === "idle") {
setState("recording")
} else if (state === "recording") {
setState("processing")
setTimeout(() => {
setState("success")
setTimeout(() => {
setState("idle")
}, 1500)
}, 1000)
}
}
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.altKey && e.code === "Space") {
e.preventDefault()
handlePress()
}
}
window.addEventListener("keydown", handleKeyDown)
return () => window.removeEventListener("keydown", handleKeyDown)
}, [state])
return (
<div className="flex min-h-[200px] w-full items-center justify-center">
<VoiceButton
label="Voice"
trailing="⌥Space"
state={state}
onPress={handlePress}
className="min-w-[180px]"
/>
</div>
)
}
Installation
pnpm dlx @elevenlabs/agents-cli@latest components add voice-button
Usage
import { VoiceButton } from "@/components/ui/voice-button"
Basic Usage
const [state, setState] = useState<"idle" | "recording" | "processing">("idle")
<VoiceButton
state={state}
onPress={() => {
if (state === "idle") {
setState("recording")
} else {
setState("processing")
}
}}
/>
With Label and Keyboard Shortcut
<VoiceButton
state="idle"
label="Press to speak"
trailing="⌥Space"
onPress={() => console.log("Button pressed")}
/>
Different States
{
/* Idle state */
}
;<VoiceButton state="idle" />
{
/* Recording with waveform */
}
;<VoiceButton state="recording" />
{
/* Processing */
}
;<VoiceButton state="processing" />
{
/* Success feedback */
}
;<VoiceButton state="success" />
{
/* Error feedback */
}
;<VoiceButton state="error" />
Icon Button
import { MicIcon } from "lucide-react"
;<VoiceButton state="idle" size="icon" icon={<MicIcon />} />
Custom Styling
<VoiceButton
state="recording"
variant="default"
size="lg"
className="w-full"
waveformClassName="bg-primary/10"
/>
Auto-transitioning States
const [state, setState] = useState<VoiceButtonState>("idle")
const handlePress = () => {
if (state === "idle") {
setState("recording")
} else if (state === "recording") {
setState("processing")
// Simulate API call
setTimeout(() => {
setState("success")
// Auto-return to idle after feedback
}, 2000)
}
}
;<VoiceButton state={state} onPress={handlePress} />
API Reference
VoiceButton
A button component with multiple states for voice recording workflows, including live waveform visualization.
Props
Prop | Type | Default | Description |
---|---|---|---|
state | "idle" | "recording" | "processing" | "success" | "error" | "idle" | Current state of the voice button |
onPress | () => void | - | Callback when button is clicked |
label | ReactNode | - | Content to display on the left side |
trailing | ReactNode | - | Content to display on the right (e.g., shortcuts) |
icon | ReactNode | - | Icon to display when idle (for icon size buttons) |
variant | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "outline" | Button variant |
size | "default" | "sm" | "lg" | "icon" | "default" | Button size |
className | string | - | Optional CSS classes for the button |
waveformClassName | string | - | Optional CSS classes for the waveform container |
feedbackDuration | number | 1500 | Duration in ms to show success/error states |
...props | HTMLButtonElement | - | All standard button element props |
VoiceButtonState Type
type VoiceButtonState =
| "idle"
| "recording"
| "processing"
| "success"
| "error"
Features
- State Management: Five distinct states (idle, recording, processing, success, error)
- Live Waveform: Displays real-time audio visualization during recording
- Automatic Transitions: Success/error states auto-transition back to idle
- Keyboard Shortcuts: Display keyboard shortcuts in the trailing slot
- Flexible Layouts: Supports label/trailing content or icon-only mode
- Customizable Feedback: Configurable duration for success/error states
- Accessibility: Proper ARIA labels and button semantics
Notes
- Integrates with the LiveWaveform component for audio visualization
- Success state shows a checkmark icon with automatic timeout
- Error state shows an X icon with automatic timeout
- Processing state displays a subtle pulsing animation
- Recording state activates the live waveform visualization
- Uses the Button component as base with all its variants
- Waveform only appears in recording state
- Feedback states (success/error) automatically return to idle after
feedbackDuration
- Compatible with all button sizes and variants
Deploy and Scale Agents with ElevenLabs
ElevenLabs delivers the infrastructure and developer experience you need to ship reliable audio & agent applications at scale.
Talk to an expert