"use client"
import { useState } from "react"
import type { ElevenLabs } from "@elevenlabs/elevenlabs-js"
import { VoicePicker } from "@/components/ui/voice-picker"
const voices: ElevenLabs.Voice[] = [
{
voiceId: "21m00Tcm4TlvDq8ikWAM",
name: "Rachel",
category: "premade",
labels: {
accent: "american",
descriptive: "casual",
age: "young",
gender: "female",
language: "en",
use_case: "conversational",
},
description:
"Matter-of-fact, personable woman. Great for conversational use cases.",
previewUrl:
"https://storage.googleapis.com/eleven-public-prod/premade/voices/21m00Tcm4TlvDq8ikWAM/b4928a68-c03b-411f-8533-3d5c299fd451.mp3",
},
{
voiceId: "29vD33N1CtxCmqQRPOHJ",
name: "Drew",
category: "premade",
labels: {
accent: "american",
description: "well-rounded",
age: "middle_aged",
gender: "male",
use_case: "news",
},
previewUrl:
"https://storage.googleapis.com/eleven-public-prod/premade/voices/29vD33N1CtxCmqQRPOHJ/b99fc51d-12d3-4312-b480-a8a45a7d51ef.mp3",
},
{
voiceId: "2EiwWnXFnvU5JabPnv8n",
name: "Clyde",
category: "premade",
labels: {
accent: "american",
descriptive: "intense",
age: "middle_aged",
gender: "male",
language: "en",
use_case: "characters_animation",
},
description: "Great for character use-cases",
previewUrl:
"https://storage.googleapis.com/eleven-public-prod/premade/voices/2EiwWnXFnvU5JabPnv8n/65d80f52-703f-4cae-a91d-75d4e200ed02.mp3",
},
]
export function VoicePickerDemo() {
const [selectedVoice, setSelectedVoice] = useState<string>(
"21m00Tcm4TlvDq8ikWAM"
)
const [open, setOpen] = useState(false)
return (
<div className="w-full max-w-lg">
<VoicePicker
voices={voices}
value={selectedVoice}
onValueChange={(value) => {
setSelectedVoice(value)
// Keep dropdown open after selection
setOpen(true)
}}
open={open}
onOpenChange={setOpen}
placeholder="Select a voice..."
/>
</div>
)
}
Installation
pnpm dlx @elevenlabs/agents-cli@latest components add voice-picker
Usage
import { VoicePicker } from "@/components/ui/voice-picker"
Basic Usage
import { ElevenLabs } from "@elevenlabs/elevenlabs-js"
const voices: ElevenLabs.Voice[] = [
{
voice_id: "21m00Tcm4TlvDq8ikWAM",
name: "Rachel",
preview_url: "https://example.com/rachel-preview.mp3",
// ... other voice properties
},
// ... more voices
]
const [selectedVoice, setSelectedVoice] = useState("")
<VoicePicker
voices={voices}
value={selectedVoice}
onValueChange={setSelectedVoice}
/>
Controlled vs Uncontrolled
{
/* Controlled */
}
;<VoicePicker
voices={voices}
value={selectedVoice}
onValueChange={setSelectedVoice}
/>
{
/* Uncontrolled */
}
;<VoicePicker
voices={voices}
onValueChange={(voiceId) => console.log("Selected:", voiceId)}
/>
Control Open State
const [open, setOpen] = useState(false)
<VoicePicker
voices={voices}
open={open}
onOpenChange={setOpen}
value={selectedVoice}
onValueChange={setSelectedVoice}
/>
Custom Placeholder
<VoicePicker
voices={voices}
placeholder="Choose your voice..."
value={selectedVoice}
onValueChange={setSelectedVoice}
/>
Fetching Voices from ElevenLabs API
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js"
const [voices, setVoices] = useState<ElevenLabs.Voice[]>([])
useEffect(() => {
const client = new ElevenLabsClient({
apiKey: process.env.ELEVENLABS_API_KEY,
})
client.voices.getAll().then((response) => {
setVoices(response.voices)
})
}, [])
<VoicePicker
voices={voices}
value={selectedVoice}
onValueChange={setSelectedVoice}
/>
API Reference
VoicePicker
A searchable dropdown for selecting ElevenLabs voices with audio preview and orb visualization.
Props
Prop | Type | Default | Description |
---|---|---|---|
voices | ElevenLabs.Voice[] | - | Required. Array of ElevenLabs voices |
value | string | - | Selected voice ID (controlled) |
onValueChange | (value: string) => void | - | Callback when selection changes |
placeholder | string | "Select a voice..." | Placeholder text when no voice selected |
className | string | - | Optional CSS classes for the trigger button |
open | boolean | - | Control popover open state |
onOpenChange | (open: boolean) => void | - | Callback when popover open state changes |
Features
- Search Functionality: Filter voices by name with built-in search
- Audio Preview: Play voice samples with play/pause controls
- Orb Visualization: Visual representation of each voice with the Orb component
- Keyboard Navigation: Full keyboard support for accessibility
- Controlled/Uncontrolled: Supports both controlled and uncontrolled patterns
- ElevenLabs Integration: Works seamlessly with ElevenLabs Voice API
- Audio Player: Integrated audio playback with shared state management
Notes
- Built on top of Command, Popover, and AudioPlayer components
- Requires
@elevenlabs/elevenlabs-js
for ElevenLabs Voice types - Each voice displays with an Orb visualization and preview audio
- Audio playback is managed by AudioPlayerProvider for consistent state
- Search is case-insensitive and filters by voice name
- Supports both controlled (
value
/onValueChange
) and uncontrolled modes - Open state can be controlled externally via
open
/onOpenChange
props - Keyboard accessible with standard combobox patterns
- Preview URLs from ElevenLabs Voice objects are used for audio playback
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