A composable component for displaying interactive, synchronized transcripts from AI SDK transcribe() results with click-to-seek functionality.
The Transcription component provides a flexible render props interface for
displaying audio transcripts with synchronized playback. It automatically
highlights the current segment based on playback time and supports click-to-seek
functionality for interactive navigation.
See scripts/transcription.tsx for this example.
npx ai-elements@latest add transcription
- Render props pattern for maximum flexibility
- Automatic segment highlighting based on current time
- Click-to-seek functionality for interactive navigation
- Controlled and uncontrolled component patterns
- Automatic filtering of empty segments
- Visual state indicators (active, past, future)
- Built on Radix UI's
useControllableStatefor flexible state management - Full TypeScript support with AI SDK transcription types
Root component that provides context and manages transcript state. Uses render props pattern for rendering segments.
| Prop | Type | Default | Description |
|---|---|---|---|
segments | TranscriptionSegment[] | - | Array of transcription segments from AI SDK transcribe() function. |
currentTime | number | 0 | Current playback time in seconds (controlled). |
onSeek | (time: number) => void | - | Callback fired when a segment is clicked or when currentTime changes. |
children | (segment: TranscriptionSegment, index: number) => ReactNode | - | Render function that receives each segment and its index. |
...props | Omit<React.ComponentProps< | - | Any other props are spread to the root div element. |
Individual segment button with automatic state styling and click-to-seek functionality.
| Prop | Type | Default | Description |
|---|---|---|---|
segment | TranscriptionSegment | - | The transcription segment data. |
index | number | - | The segment index. |
...props | React.ComponentProps< | - | Any other props are spread to the button element. |
The component uses a render props pattern where the children prop is a
function that receives each segment and its index. This provides maximum
flexibility for custom rendering while still benefiting from automatic state
management and context.
Segments are automatically styled based on their relationship to the current playback time:
- Active (
isActive): WhencurrentTimeis within the segment's time range. Styled with primary color. - Past (
isPast): WhencurrentTimeis after the segment's end time. Styled with muted foreground. - Future: When
currentTimeis before the segment's start time. Styled with dimmed muted foreground.
When onSeek is provided, segments become interactive buttons. Clicking a
segment calls onSeek with the segment's start time, allowing your audio/video
player to seek to that position.
The component automatically filters out segments with empty or whitespace-only text to avoid rendering unnecessary elements.
Uses Radix UI's useControllableState hook to support both controlled and
uncontrolled patterns. When currentTime is provided, the component operates in
controlled mode. Otherwise, it maintains its own internal state.
The component expects segments from the AI SDK transcribe() function:
The component uses data attributes for custom styling:
data-slot="transcription": Root containerdata-slot="transcription-segment": Individual segment buttondata-active: Present on the currently playing segmentdata-index: The segment's index in the array
Default segment appearance:
- Active segment:
text-primary(primary brand color) - Past segments:
text-muted-foreground - Future segments:
text-muted-foreground/60(dimmed) - Interactive segments:
cursor-pointer hover:text-foreground - Non-interactive segments:
cursor-default
- Uses semantic
<button>elements for interactive segments - Full keyboard navigation support
- Proper button semantics for screen readers
data-activeattribute for assistive technology- Hover and focus states for keyboard users
- Empty or whitespace-only segments are automatically filtered out
- The component uses
flex-wrapfor responsive text flow - Segments maintain inline layout with
gap-1spacing text-smandleading-relaxedprovide comfortable reading- Click events on segments still fire the
onClickhandler if provided - The
onSeekcallback is called both when segments are clicked and when controlledcurrentTimechanges