Voice session

The control bar for a live voice call, with mute, captions, a timer and a button to hang up.

Loading preview…

Install

  1. 1

    Run this command in your Tailwind CSS project. It adds components/ai/voice-session.tsx and installs its dependencies.

    $ npx shadcn@latest add https://gradientdeck.com/ai-components/r/voice-session.json

Usage & API

Example

voice-session.tsx
import { VoiceSession } from "@/components/ai/voice-session"

<VoiceSession
  state={state}
  elapsed={1}
  muted={true}
  onMutedChange={() => {}}
  captions={true}
  onCaptionsChange={() => {}}
  onEnd={() => {}}
/>

Props VoiceSession

PropType & descriptionRequired
stateVoiceStateRequired
elapsednumberSeconds since the call startedRequired
mutedbooleanRequired
onMutedChange(muted: boolean) => voidRequired
captionsbooleanRequired
onCaptionsChange(on: boolean) => voidRequired
caption{ speaker: string; text: string }The line being spoken right now, shown when captions are on.Optional
onEnd() => voidRequired
endedbooleanOptional
onRestart() => voidOptional
levelnumber0–1 loudness for the orb. Leave out to simulate.Optional

Dependencies

  • React
  • Tailwind CSS
  • motion
  • lucide-react
Implementation notes

Call bar is the only variant. The group is labelled Voice call. While the call is up, the left cluster is the aura in a round well, then status and the clock. The clock has a screen-reader prefix, Call time. Mute shows a mic or a mic-off icon. Captions shows the matching captions icon. End call is the red phone button. The caption card, when visible, is at least a short block tall so the bar does not jump as lines change. When ended is true, none of the round buttons render, and Call again is the warm filled button on the right. The preview script includes empty thinking steps, so the caption panel can show a speaker with no words, plus the caret. Reduced motion drops the panel's motion and the caret. Restart is whatever onRestart you pass. The demo clears ended and rewinds its script.

Choosing a layout

Use it as the persistent control for a spoken session, the piece that stays put while the conversation moves. People need mute and hang up without hunting through a transcript, and they need the state named next to the timer so a silence is either listening or thinking. Keep the bar even when you also show Live transcript. The caption panel is one line, the line being spoken now, not the history. Pair them when the call is long. Pair the bar with Microphone picker on the way in, and with Voice picker where the assistant's voice is a setting rather than a mid-call control. This bar does not list devices or voices.

Skip it for a clip with a duration and a playhead. A generated take belongs with a player, not a hang-up button. Skip it if you only need the picture. Voice orb has five drawings and no call controls. Skip the caption panel if a full transcript is already on screen, and pass captions as false or omit the caption so the panel stays closed. The bar is a single row. It is not a dial pad, a hold button, or a transfer menu. Those controls are not in the file. After hang up, the only action drawn is Call again.

What does mute change besides the icon?

The button toggles the muted prop through onMutedChange. If state is listening while muted, the status word becomes Muted and the small aura draws as ready with level 0. Speaking and thinking keep their labels. Mute does not stop a track. The parent has to mute the real microphone when the boolean changes.

What is on screen after hang up?

onEnd fires from the red button. When you pass ended, the bar reads Call ended, shows the elapsed clock, and offers Call again, which calls onRestart. The aura, mute, captions, and the caption panel all unmount. The component does not set ended by itself.