165

Voice Button

PreviousNext

Interactive button with voice recording states, live waveform visualization, and automatic feedback transitions.

<script setup lang="ts">
import { VoiceButton } from '@/components/elevenlabs-ui/voice-button'
import { onMounted, onUnmounted, ref } from 'vue'

type VoiceButtonState = 'idle' | 'recording' | 'processing' | 'success' | 'error'

const state = ref<VoiceButtonState>('idle')

function handlePress() {
  if (state.value === 'idle') {
    state.value = 'recording'
  }
  else if (state.value === 'recording') {
    state.value = 'processing'

    // Simulate an API call / transcription
    setTimeout(() => {
      state.value = 'success'

      // Revert to idle after the feedback duration
      setTimeout(() => {
        state.value = 'idle'
      }, 1500)
    }, 1000)
  }
}

function handleKeyDown(e: KeyboardEvent) {
  // ⌥ (Alt) + Space
  if (e.altKey && e.code === 'Space') {
    e.preventDefault()
    handlePress()
  }
}

onMounted(() => {
  window.addEventListener('keydown', handleKeyDown)
})

onUnmounted(() => {
  window.removeEventListener('keydown', handleKeyDown)
})
</script>

<template>
  <div class="flex min-h-[200px] w-full items-center justify-center p-4">
    <VoiceButton
      label="Voice"
      trailing="⌥Space"
      :state="state"
      class="min-w-[180px]"
      @press="handlePress"
    />
  </div>
</template>

Installation

pnpm dlx elevenlabs-ui-vue@latest add voice-button

Usage

import { VoiceButton } from "@/components/elevenlabs-ui/voice-button"

Basic Usage

<script setup lang="ts"> 
const state = ref<'idle' | 'recording' | 'processing'>('idle')

const handlePress = () => {
  if (state.value === 'idle') {
    state.value = 'recording'
  } else {
    state.value = 'processing'
  }
}
</script>

<template>
 <VoiceButton
   :state="state"
   @press="handlePress"
 />
</template>

With Label and Keyboard Shortcut

<template>
  <VoiceButton
   state="idle"
   label="Press to speak"
   trailing="⌥Space"
   @press="console.log("Button pressed")"
 />
</template>

Different States

<script setup lang="ts">
import { VoiceButton } from '@/components/elevenlabs-ui/voice-button'
</script>

<template>
  <div>
    <!-- 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" />
   </div>
</template>

Icon Button

<script setup lang="ts">
 import { MicIcon } from 'lucide-vue-next' 
 import { VoiceButton } from '@/components/elevenlabs-ui/voice-button'
</script>

<template>
 <VoiceButton state="idle" size="icon">
  <template #icon>
    <MicIcon />
  </template>
 </VoiceButton>
</template>

Custom Styling

<template>
  <VoiceButton
    state="recording"
    variant="default"
    size="lg"
    class="w-full"
    waveformClass="bg-primary/10"
  />
</template>

Auto-transitioning States

<script setup lang="ts">
import { ref } from 'vue'
import {
  VoiceButton,
  type VoiceButtonState,
} from '@/components/elevenlabs-ui/voice-button'

const state = ref<VoiceButtonState>('idle')

const handlePress = () => {
  if (state.value === 'idle') {
   state.value = 'recording'
  } else if (state.value === 'recording') {
    state.value = 'processing'
    // Simulate API call
    setTimeout(() => {
      state.value = 'success'
      // Auto-return to idle after feedback
    }, 2000)
  }
}
</script>

<template>
 <VoiceButton :state="state" @press="handlePress" />
</template>

API Reference

VoiceButton

A button component with multiple states for voice recording workflows, including live waveform visualization.

Props

PropTypeDefaultDescription
state"idle" | "recording" | "processing" | "success" | "error""idle"Current state of the voice button
labelany-Content to display on the left side
trailingany-Content to display on the right (e.g., shortcuts)
iconany-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
classstring-Optional CSS classes for the button
waveformClassstring-Optional CSS classes for the waveform container
feedbackDurationnumber1500Duration in ms to show success/error states
...propsHTMLAttributes-All standard button element props

Emits

EventTypeDescription
press() => voidCallback when when button is clicked

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