<script setup lang="ts">
import type { CharacterAlignmentResponseModel } from '@elevenlabs/elevenlabs-js/api/types/CharacterAlignmentResponseModel'
import {
TranscriptViewer,
TranscriptViewerAudio,
TranscriptViewerPlayPauseButton,
TranscriptViewerScrubBar,
TranscriptViewerWords,
} from '@/components/elevenlabs-ui/transcript-viewer'
import { Skeleton } from '@/components/ui/skeleton'
import { PauseIcon, PlayIcon } from 'lucide-vue-next'
import { onMounted, ref } from 'vue'
const audioSrc = '/sounds/transcript-viewer/transcript-viewer-audio.mp3'
const alignment = ref<CharacterAlignmentResponseModel | undefined>(undefined)
onMounted(() => {
fetch('/sounds/transcript-viewer/transcript-viewer-alignment.json')
.then(res => res.json())
.then((data) => {
alignment.value = data
})
})
</script>
<template>
<div class="flex w-full flex-col gap-4">
<TranscriptViewer
:key="audioSrc"
class="bg-card w-full rounded-xl border p-4"
:audio-src="audioSrc"
audio-type="audio/mpeg"
:alignment="
alignment ?? {
characters: [],
characterStartTimesSeconds: [],
characterEndTimesSeconds: [],
}
"
>
<TranscriptViewerAudio class="sr-only" />
<template v-if="alignment">
<TranscriptViewerWords />
<div class="flex items-center gap-3">
<TranscriptViewerScrubBar />
</div>
</template>
<template v-else>
<div class="flex w-full flex-col gap-3">
<Skeleton class="h-5 w-full" />
<Skeleton class="mb-4 h-5 w-1/2" />
<Skeleton class="h-2 w-full" />
<div class="-mt-1 flex items-center justify-between">
<Skeleton class="h-2 w-6" />
<Skeleton class="h-2 w-6" />
</div>
</div>
</template>
<TranscriptViewerPlayPauseButton
class="w-full cursor-pointer"
size="default"
:disabled="!alignment"
>
<template #default="{ isPlaying }">
<PauseIcon v-if="isPlaying" class="size-4" />
<PlayIcon v-else class="size-4" />
<span>{{ isPlaying ? 'Pause' : 'Play' }}</span>
</template>
</TranscriptViewerPlayPauseButton>
</TranscriptViewer>
</div>
</template>Installation
pnpm dlx elevenlabs-ui-vue@latest add transcript-viewer
Usage
<script setup lang="ts">
import {
TranscriptViewer,
TranscriptViewerAudio,
TranscriptViewerPlayPauseButton,
TranscriptViewerScrubBar,
TranscriptViewerWords,
type CharacterAlignmentResponseModel,
} from "@/components/elevenlabs-ui/transcript-viewer"
const audioSrc = "/path/to/audio.mp3"
const alignment: CharacterAlignmentResponseModel = {
characters: ["H", "e", "l", "l", "o"],
characterStartTimesSeconds: [0, 0.1, 0.2, 0.3, 0.4],
characterEndTimesSeconds: [0.1, 0.2, 0.3, 0.4, 0.5],
}
</script>
<template>
<TranscriptViewer :audio-src="audioSrc" :alignment="alignment">
<TranscriptViewerAudio />
<TranscriptViewerWords />
<div class="flex items-center gap-3">
<TranscriptViewerPlayPauseButton />
<TranscriptViewerScrubBar />
</div>
</TranscriptViewer>
</template>API Reference
TranscriptViewer
The main container for the transcript viewer components. It manages the state and provides context to its children.
Props
| Prop | Type | Description |
|---|---|---|
audioSrc | string | Required. The URL of the audio file. |
audioType | AudioType | Optional. The type of the audio file. Defaults to audio/mpeg. |
alignment | CharacterAlignmentResponseModel | Required. The alignment data for the transcript. |
segmentComposer | SegmentComposer | Optional. A function to compose transcript segments. |
hideAudioTags | boolean | Optional. If true, ElevenLabs tags (e.g. [Excited]) are hidden from the transcript. Defaults to true. |
class | string | Optional. Additional CSS classes. |
Emits
| Event | Type | Description |
|---|---|---|
play | () => void | Optional. Callback when audio playback starts. |
pause | () => void | Optional. Callback when audio playback is paused. |
timeUpdate | (time: number) => void | Optional. Callback when the current time of the audio updates. |
ended | () => void | Optional. Callback when the audio playback ends. |
durationChange | (duration: number) => void | Optional. Callback when the audio duration is available. |
TranscriptViewerWords
Displays the transcript words. It uses the context from TranscriptViewer to highlight words as the audio plays.
Props
| Prop | Type | Description |
|---|---|---|
renderWord | (props: { word: TranscriptWord, status: "spoken" | "unspoken" | "current" }) => VNode | Optional. Custom render function for each word. |
renderGap | (props: { segment: TranscriptGap, status: "spoken" | "unspoken" | "current" }) => VNode | Optional. Custom render function for gaps between words. |
wordClass | string | Optional. Additional class names for each word <span>. |
gapClass | string | Optional. Additional class names for each gap <span>. |
class | string | Optional. Additional CSS classes. |
TranscriptViewerAudio
The underlying HTML <audio> element. It's controlled by the TranscriptViewer. You can pass standard <audio> element props. By default it is hidden.
This component accepts standard HTMLAttributes attributes.
TranscriptViewerPlayPauseButton
A button to play or pause the audio. It uses the context from TranscriptViewer. It accepts props for the Button component.
TranscriptViewerScrubBar
A scrub bar for seeking through the audio timeline. It's a context-aware implementation of the ScrubBar component.
Props
| Prop | Type | Description |
|---|---|---|
showTimeLabels | boolean | Optional. If true, displays current time and remaining time labels. Defaults to true. |
labelsClass | string | Optional. Class names for the time labels container. |
trackClass | string | Optional. Class names for the scrub bar track. |
progressClass | string | Optional. Class names for the scrub bar progress indicator. |
thumbClass | string | Optional. Class names for the scrub bar thumb. |
class | string | Optional. Additional CSS classes. |
useTranscriptViewerContext
A composable to access the transcript viewer's state and controls. Must be used within a TranscriptViewer.
Returns an object with the following properties:
audioRef: Ref to the audio element.segments: All transcript segments.words: All word segments.spokenSegments: Segments that have been spoken.unspokenSegments: Segments that have not been spoken.currentWord: The currently spoken word segment.currentSegmentIndex: The index of the current segment.currentWordIndex: The index of the current word.duration: The total duration of the audio.currentTime: The current playback time.isPlaying:trueif audio is playing.isScrubbing:trueif the user is scrubbing.play(): Function to start playback.pause(): Function to pause playback.seekToTime(time): Function to seek to a specific time.seekToWord(word): Function to seek to a specific word.startScrubbing(): Function to call on scrub start.endScrubbing(): Function to call on scrub end.
useTranscriptViewer
A headless composable to manage a transcript viewer's state, controls, and playback. This is used internally by the TranscriptViewer components.
Accepts an object with the following properties:
| Prop | Type | Description |
|---|---|---|
alignment | CharacterAlignmentResponseModel | Required. The alignment data for the transcript. |
segmentComposer | SegmentComposer | Optional. A function to compose transcript segments. |
hideAudioTags | boolean | Optional. If true, ElevenLabs tags (e.g. [Excited]) are hidden from the transcript. Defaults to true. |
onPlay | () => void | Optional. Callback when audio playback starts. |
onPause | () => void | Optional. Callback when audio playback is paused. |
onTimeUpdate | (time: number) => void | Optional. Callback when the current time of the audio updates. |
onEnded | () => void | Optional. Callback when the audio playback ends. |
onDurationChange | (duration: number) => void | Optional. Callback when the audio duration is available. |
Returns an object with the following properties:
audioRef: Ref to the audio element.segments: All transcript segments.words: All word segments.spokenSegments: Segments that have been spoken.unspokenSegments: Segments that have not been spoken.currentWord: The currently spoken word segment.currentSegmentIndex: The index of the current segment.currentWordIndex: The index of the current word.duration: The total duration of the audio.currentTime: The current playback time.isPlaying:trueif audio is playing.isScrubbing:trueif the user is scrubbing.play(): Function to start playback.pause(): Function to pause playback.seekToTime(time): Function to seek to a specific time.seekToWord(word): Function to seek to a specific word.startScrubbing(): Function to call on scrub start.endScrubbing(): Function to call on scrub end.