Voice Selector

A composable dialog component for selecting AI voices with metadata display and search functionality.

The VoiceSelector component provides a flexible and composable interface for selecting AI voices. Built on shadcn-vue's Dialog and Command components, it features a searchable voice list with support for metadata display (gender, accent, age), grouping, and customizable layouts. The component includes a context provider for accessing voice selection state from any nested component.

Install using CLI

AI Elements Vue
shadcn-vue CLI
npx ai-elements-vue@latest add voice-selector

Install Manually

Copy and paste the following code into your project.

VoiceSelector.vue
VoiceSelectorTrigger.vue
VoiceSelectorContent.vue
VoiceSelectorDialog.vue
VoiceSelectorInput.vue
VoiceSelectorList.vue
VoiceSelectorEmpty.vue
VoiceSelectorGroup.vue
VoiceSelectorItem.vue
VoiceSelectorShortcut.vue
VoiceSelectorSeparator.vue
VoiceSelectorGender.vue
VoiceSelectorAccent.vue
VoiceSelectorAge.vue
VoiceSelectorName.vue
VoiceSelectorDescription.vue
VoiceSelectorAttributes.vue
VoiceSelectorBullet.vue
VoiceSelectorPreview.vue
context.ts
index.ts
<script setup lang="ts">
import { Dialog } from '@repo/shadcn-vue/components/ui/dialog'
import { useVModel } from '@vueuse/core'
import { provide } from 'vue'
import { VoiceSelectorKey } from './context'

type VoiceSelectorProps = InstanceType<typeof Dialog>['$props']

interface Props extends /* @vue-ignore */ VoiceSelectorProps {
  value?: string
  defaultValue?: string
  open?: boolean
  defaultOpen?: boolean
}

const props = withDefaults(defineProps<Props>(), {
  open: undefined,
  defaultOpen: false,
})

const emit = defineEmits<{
  (e: 'update:value', value: string | undefined): void
  (e: 'update:open', open: boolean): void
  (e: 'valueChange', value: string | undefined): void
  (e: 'openChange', open: boolean): void
}>()

const value = useVModel(props, 'value', emit, {
  defaultValue: props.defaultValue,
  passive: (props.value === undefined) as any,
})

const open = useVModel(props, 'open', emit, {
  defaultValue: props.defaultOpen,
  passive: (props.open === undefined) as any,
})

function setValue(newValue: string | undefined) {
  value.value = newValue
  emit('valueChange', newValue)
}

function setOpen(newOpen: boolean) {
  open.value = newOpen
  emit('openChange', newOpen)
}

provide(VoiceSelectorKey, {
  value,
  setValue,
  open,
  setOpen,
})
</script>

<template>
  <Dialog
    :open="open"
    @update:open="setOpen"
  >
    <slot />
  </Dialog>
</template>

Features

  • Fully composable architecture with granular control components
  • Built on shadcn-vue Dialog and Command components
  • Vue Provide/Inject API for accessing state in nested components
  • Searchable voice list with real-time filtering
  • Support for voice metadata with icons and emojis (gender icons, accent flags, age)
  • Voice preview button with play/pause/loading states
  • Voice grouping with separators and bullet dividers
  • Keyboard navigation support
  • Controlled and uncontrolled component patterns
  • Full TypeScript support with proper types for all components

Props

<VoiceSelector />

Root Dialog component that provides context for all child components. Manages both voice selection and dialog open states.

v-model:valuestring
The selected voice ID (controlled).
defaultValuestring
The default selected voice ID (uncontrolled).
v-model:openboolean
The open state of the dialog (controlled).
defaultOpenboolean
The default open state (uncontrolled).
...propsDialogProps
Any other props are spread to the Dialog component.

<VoiceSelectorTrigger />

Button or element that opens the voice selector dialog.

asChildboolean
Change the default rendered element for the one passed as a child, merging their props and behavior.
...propsDialogTriggerProps
Any other props are spread to the DialogTrigger component.

<VoiceSelectorContent />

Container for the Command component and voice list, rendered inside the dialog.

titlestring
The title for screen readers. Hidden visually but accessible to assistive technologies.
classstring
Additional CSS classes to apply to the dialog content.
...propsDialogContentProps
Any other props are spread to the DialogContent component.

<VoiceSelectorDialog />

Alternative dialog implementation using CommandDialog for a full-screen command palette style.

...propsCommandDialogProps
Any other props are spread to the CommandDialog component.

<VoiceSelectorInput />

Search input for filtering voices.

placeholderstring
Placeholder text for the search input.
classstring
Additional CSS classes to apply.
...propsCommandInputProps
Any other props are spread to the CommandInput component.

<VoiceSelectorList />

Scrollable container for voice items and groups.

...propsCommandListProps
Any other props are spread to the CommandList component.

<VoiceSelectorEmpty />

Message shown when no voices match the search query.

...propsCommandEmptyProps
Any other props are spread to the CommandEmpty component.

<VoiceSelectorGroup />

Groups related voices together with an optional heading.

headingstring
The heading text for the group.
...propsCommandGroupProps
Any other props are spread to the CommandGroup component.

<VoiceSelectorItem />

Selectable item representing a voice.

valuerequiredstring
The unique identifier for this voice. Used for search filtering.
classstring
Additional CSS classes to apply.
...propsCommandItemProps
Any other props are spread to the CommandItem component.

<VoiceSelectorSeparator />

Visual separator between voice groups.

...propsCommandSeparatorProps
Any other props are spread to the CommandSeparator component.

<VoiceSelectorShortcut />

Displays keyboard shortcuts for voice items.

...propsCommandShortcutProps
Any other props are spread to the CommandShortcut component.

<VoiceSelectorName />

Displays the voice name with proper styling.

classstring
Additional CSS classes to apply.

<VoiceSelectorGender />

Displays the voice gender metadata with icons from Lucide. Supports multiple gender identities with corresponding icons.

value"male" | "female" | "transgender" | "androgyne" | "non-binary" | "intersex"
The gender value that determines which icon to display. Supported values: "male" (Mars), "female" (Venus), "transgender", "androgyne", "non-binary", "intersex". Defaults to a small circle if no value matches.
classstring
Additional CSS classes to apply.

<VoiceSelectorAccent />

Displays the voice accent metadata with emoji flags representing different countries/regions.

valuestring
The accent value that determines which flag emoji to display. Supports 27 different accents including: "american" 🇺🇸, "british" 🇬🇧, "australian" 🇦🇺, "canadian" 🇨🇦, "irish" 🇮🇪, "scottish" 🏴󠁧󠁢󠁳󠁣󠁴󠁿, "indian" 🇮🇳, "south-african" 🇿🇦, "new-zealand" 🇳🇿, "spanish" 🇪🇸, "french" 🇫🇷, "german" 🇩🇪, "italian" 🇮🇹, "portuguese" 🇵🇹, "brazilian" 🇧🇷, "mexican" 🇲🇽, "argentinian" 🇦🇷, "japanese" 🇯🇵, "chinese" 🇨🇳, "korean" 🇰🇷, "russian" 🇷🇺, "arabic" 🇸🇦, "dutch" 🇳🇱, "swedish" 🇸🇪, "norwegian" 🇳🇴, "danish" 🇩🇰, "finnish" 🇫🇮, "polish" 🇵🇱, "turkish" 🇹🇷, "greek" 🇬🇷. Also accepts any custom string value.
classstring
Additional CSS classes to apply.

<VoiceSelectorAge />

Displays the voice age metadata with muted styling and tabular numbers for consistent alignment.

classstring
Additional CSS classes to apply.

<VoiceSelectorDescription />

Displays a description for the voice with muted styling.

classstring
Additional CSS classes to apply.

<VoiceSelectorAttributes />

Container for grouping voice attributes (gender, accent, age) together. Use with VoiceSelectorBullet for separation.

classstring
Additional CSS classes to apply.

<VoiceSelectorBullet />

Displays a bullet separator (•) between voice attributes. Hidden from screen readers via aria-hidden.

classstring
Additional CSS classes to apply.

<VoiceSelectorPreview />

A button that allows users to preview/play a voice sample before selecting it. Shows play, pause, or loading icons based on state.

playingboolean
Whether the voice is currently playing. Shows pause icon when true.
loadingboolean
Whether the voice preview is loading. Shows loading spinner and disables the button.
classstring
Additional CSS classes to apply.

Emits

<VoiceSelector />

update:valuestring | undefined
Emitted when the selected voice changes (for v-model).
valueChangestring | undefined
Callback emitted when the selected voice changes.
update:openboolean
Emitted when the open state changes (for v-model).
openChangeboolean
Callback emitted when the open state changes.

<VoiceSelectorItem />

selectstring
Emitted when the voice is selected with the voice value.

<VoiceSelectorPreview />

playvoid
Emitted when the preview button is clicked.

Composables

useVoiceSelector()

A custom composable for accessing the voice selector context. This composable allows you to access and control the voice selection state from any component nested within VoiceSelector.

<script setup lang="ts">
import { useVoiceSelector } from '@repo/elements/voice-selector'

const { value, setValue, open, setOpen } = useVoiceSelector('MyComponent')
</script>

<template>
  <div>
    <p>Selected voice: {{ value ?? 'None' }}</p>
    <button @click="setOpen(!open)">
      Toggle Dialog
    </button>
  </div>
</template>

Return Value

valueRef<string | undefined>
The currently selected voice ID.
setValue(value: string | undefined) => void
Function to update the selected voice ID.
openRef<boolean | undefined>
Whether the dialog is currently open.
setOpen(open: boolean) => void
Function to control the dialog open state.