
Features
- Automatic scrolling – The transcript automatically highlights the current line and scrolls to it
- Click to jump – Click on any line in the transcript to jump to that moment in the video
- Movable window – Position the transcript anywhere on the screen (desktop only)
- Adjust window size – Resize the transcript window using your mouse or keyboard
- Keyboard navigation – Use the arrow keys to move the transcript window (press ‘D’ to toggle)
- Keyboard resize mode – Use the arrow keys to adjust the size of the transcript window (press ‘R’ to toggle)
- Settings menu – Configure drag and resize modes
- Mobile optimisation – Adapts to mobile screens (< 768px) with an optimised layout
- Full-screen support – The transcript is intelligently repositioned in full-screen mode
- Search & Read – Ideal for accessibility and language learning
Quick Start
Enable transcript
<video data-vidply data-transcript="true" data-transcript-button="true">
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="en" label="English">
</video>
<script type="module">
import Player from './dist/prod/vidply.esm.min.js';
</script>
That’s it! The transcript button appears in the control bar.
Configuration options
About JavaScript
const player = new Player('#video', {
transcript: true, // Enable transcript feature
transcriptButton: true, // Show transcript button in controls
transcriptPosition: 'external' // Position mode (currently only 'external')
});
About data attributes
<video
data-vidply
data-transcript="true"
data-transcript-button="true"
src="video.mp4"
>
<track kind="captions" src="captions.vtt" srclang="en" label="English">
</video>
How it works
The transcription feature automatically performs the following steps:
- Detects subtitle tracks in your video
- Loads the VTT cue text (WebVTT)
- Creates an interactive, scrollable window
- Highlights the current line based on the video playback time
- Scrolls automatically to keep the current line visible
API methods
Show/hide transcript
const player = new Player('#video', {
transcript: true,
transcriptButton: true
});
// Show transcript window
player.transcriptManager.showTranscript();
// Hide transcript window
player.transcriptManager.hideTranscript();
// Toggle transcript visibility
player.transcriptManager.toggleTranscript();
Check status
// Check if transcript is visible
if (player.transcriptManager.isVisible) {
console.log('Transcript is showing');
}
Program-controlled operation
// Get transcript entries
console.log(player.transcriptManager.transcriptEntries);
// Get current active entry
console.log(player.transcriptManager.currentActiveEntry);
User interaction
Click to search
Users can click on any line of the transcript to jump to that point:
// This happens automatically, but you can listen for it
player.on('timeupdate', (time) => {
console.log('User jumped to:', time);
});
Drag and resize (desktop)
On desktop (>= 768px), users can:
Drag mode:
- D key – Toggle keyboard drag mode
- Arrow keys – Move window in 10-pixel increments (Shift = 50 pixels)
- Mouse drag – Drag the header of the transcript to change its position
- Home key – Reset to centre
- Esc key – Exit drag mode
Resize mode:
- R key – Switch to resize mode via the keyboard
- Arrow keys – Change window size in 10-pixel increments (Shift = 50 pixels)
- Resizing with the mouse – Drag the resize handles at the edges of the window
- Esc key – Exit resize mode
Settings menu:
- Click the settings icon (⚙️) in the header of the transcript
- Toggle between drag mode and resize mode
- Close the transcript window
Behaviour on mobile devices
On mobile devices (< 768px breakpoint):
- The transcript is displayed below the video player
- Positioned within the document flow (cannot be moved or resized)
- Optimised for scrolling and reading
- Minimum width: 300px
Positioning modes
Desktop (non-full screen)
- Displayed next to the video player
- Can be dragged to any position
- Height matches the video height
Full-screen mode
- Located in the bottom right-hand corner
- Hovers over the video
- Leaves space for controls
Mobile
- Below the video and controls
- Full width
- Maximum height of 400px
- Part of the page flow
Keyboard shortcuts
Global keyboard shortcuts (Player in focus)
| Key | Action |
|---|---|
| T | Show/hide transcript window |
| D | Toggle drag mode (when transcript is visible) |
| R | Toggle resize mode (when transcript is visible) |
Drag mode (D key – must be activated first)
| Key | Action |
|---|---|
| ← → ↑ ↓ | Move window (10px) |
| Shift + Arrow key | Move window (50px) |
| Home | Reset to centre |
| Esc | Exit drag mode |
Resize mode (R key – must be activated first)
| Key | Action |
|---|---|
| ← → | Adjust width (10px) |
| ↑ ↓ | Adjust height (10px) |
| Shift + Arrow key | Resize (50px) |
| Esc | Exit resize mode |
Transcript entries
| Key | Action |
|---|---|
| Enter / Spacebar | Jump to this point (if the entry is in focus) |
| Tab | Navigate through the transcript entries |
Layout of the transcript
Custom colours
/* Transcript window */
.vidply-transcript-window {
background: rgba(20, 20, 30, 0.95);
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* Header */
.vidply-transcript-header {
background: rgba(30, 30, 40, 0.95);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
/* Transcript entries */
.vidply-transcript-entry {
padding: 12px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
/* Active entry */
.vidply-transcript-entry-active {
background: rgba(59, 130, 246, 0.2);
border-left: 3px solid #3b82f6;
}
/* Timestamp */
.vidply-transcript-time {
color: #60a5fa;
font-weight: 600;
}
Full example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Transcript Example</title>
<link rel="stylesheet" href="dist/vidply.min.css">
<style>
body {
font-family: system-ui, sans-serif;
padding: 20px;
background: #111;
color: #fff;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
margin-bottom: 20px;
}
/* Custom transcript styling */
.vidply-transcript-window {
background: linear-gradient(135deg, rgba(30, 30, 50, 0.98), rgba(20, 20, 40, 0.98));
backdrop-filter: blur(10px);
}
.vidply-transcript-entry-active {
background: linear-gradient(90deg, rgba(139, 92, 246, 0.2), rgba(59, 130, 246, 0.2));
}
</style>
</head>
<body>
<div class="container">
<h1>Video with Interactive Transcript</h1>
<video
id="my-video"
data-vidply
data-transcript="true"
data-transcript-button="true"
width="800"
height="450"
>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions-en.vtt" srclang="en" label="English" default>
<track kind="captions" src="captions-es.vtt" srclang="es" label="Español">
</video>
<div style="margin-top: 20px;">
<button id="toggleTranscript">Toggle Transcript</button>
</div>
</div>
<script type="module">
import Player from './dist/prod/vidply.esm.min.js';
// Player is auto-initialized via data-vidply
// Get player instance
const videoElement = document.getElementById('my-video');
const player = videoElement.vidply; // Player instance stored on the media element
// Or find it manually
const allPlayers = document.querySelectorAll('[data-vidply]');
// const player = allPlayers[0].vidply;
// Manual toggle button
document.getElementById('toggleTranscript').addEventListener('click', () => {
if (player && player.transcriptManager) {
player.transcriptManager.toggleTranscript();
}
});
// Listen for transcript interactions
document.addEventListener('DOMContentLoaded', () => {
// Wait a moment for player to initialize
setTimeout(() => {
const container = document.querySelector('.vidply-player');
const video = container?.querySelector('video, audio');
if (video && video.vidply) {
const p = video.vidply;
p.on('timeupdate', (time) => {
// User can see which line is active
if (p.transcriptManager && p.transcriptManager.currentActiveEntry) {
console.log('Active transcript:', p.transcriptManager.currentActiveEntry.cue.text);
}
});
}
}, 1000);
});
</script>
</body>
</html>
Use cases
1. Accessibility
- Users of screen readers can read the transcript text
- Deaf or hard-of-hearing users have full access to the text
- Users in noisy environments can read instead of listening
2. Language learning
- Follow the native speakers
- Click here to replay difficult sections
- Read and listen at the same time
3. Search & Navigation
- Quickly skim through content
- Find specific topics
- Jump to relevant sections
4. Notes
- Cite exact quotations
- Copy text for quotations
- Learning support for educational content
5. SEO & discoverability
- Video content becomes text-searchable
- Better indexing for accessibility
- Improved discoverability of content
Requirements
Subtitle track required
At least one subtitle track is required for the transcription function:
<track kind="captions" src="captions.vtt" srclang="en" label="English">
<!-- or -->
<track kind="subtitles" src="subtitles.vtt" srclang="en" label="English">
Note: kind="descriptions" or kind="chapters" Tracks are NOT used for transcripts.
Supported streaming formats
| Platform / Format | Subtitle type | Transcript support |
|---|---|---|
| HTML5 (MP4/WebM) | WebVTT | Yes |
HLS (.m3u8) — hls.js (Chrome / Firefox / Edge / Desktop Safari) | WebVTT | Yes (Cues are loaded incrementally whilst segments are buffered; Hls.Events.SUBTITLE_FRAG_PROCESSED replay textcuesupdate) |
| HLS (.m3u8) — Native HLS on iOS / iPadOS Safari | WebVTT (via native TextTrack API) | Yes — VidPly integrates the browser’s native HLS subtitles into the subtitle menu, the transcript window and the quality menu |
| DASH (.mpd) | WebVTT | Yes (cues are loaded incrementally whilst segments are buffered) |
| DASH (.mpd) | TTML / stpp | No (TTML is rendered natively by dash.js; the transcript button is hidden) |
iOS / iPadOS: Even though
hls.jsit cannot run on iOS (no MSE), VidPly waitsaddtrack/removetrack/loadedmetadatafor the nativeHTMLMediaElement.textTrackscollection and displays each subtitle presentation via the same subtitle menu and interactive transcription as on desktop. Transcript-on-iOS now works for live and adaptive HLS streams.
For DASH streams with TTML subtitles, the subtitles are displayed on screen by dash.js, but the interactive transcript is not available. If you require transcript support for DASH, use WebVTT subtitle tracks.
WebVTT format
Subtitles must be in WebVTT format:
WEBVTT
00:00:00.000 --> 00:00:05.000
Welcome to this video tutorial.
00:00:05.000 --> 00:00:10.000
Today we'll learn about VidPly's transcript feature.
00:00:10.000 --> 00:00:15.000
It's a powerful tool for accessibility and learning.
Browser support
The transcription feature works in all modern browsers:
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
- Mobile browsers (iOS Safari, Chrome Android)
Troubleshooting
The ‘Transcript’ button is not displayed
Cause: No subtitle tracks were detected
Solution:
<!-- Add at least one caption track -->
<track kind="captions" src="captions.vtt" srclang="en" label="English">
Transcript displays “Loading...”
Cause: The VTT file is taking a long time to load or the path is incorrect
Solutions:
- Check that the file path is correct
- Check the CORS headers if loading from a different domain
- Check that the VTT file format is valid
Transcript cannot be moved on mobile devices
Expected: On mobile devices (< 768px), the transcript is NOT scrollable. It is positioned in the page flow below the video.
Transcript does not scroll automatically
Cause: JavaScript error or subtitle track not in hidden mode
Solution: Check the browser console for errors. The Transcript Manager automatically sets the track mode to hidden.
Advanced: External transcript container
You can display the transcript in a custom container (future feature):
const player = new Player('#video', {
transcript: true,
transcriptPosition: 'external',
transcriptContainer: '#my-transcript-container'
});
<div id="my-transcript-container"></div>
Note: This feature is partially implemented. Currently, the transcript is always displayed next to or below the video.
Notes on performance
- Transcript entries are generated as required when the transcript is displayed for the first time
- Automatic scrolling uses efficient
scrollIntoViewwithsmoothbehaviour - Event listeners are cleared when the transcript is destroyed
- No impact on performance when the transcript is not visible
Accessibility features
Keyboard accessibility – Full keyboard navigation
ARIA labels – Correct role and aria-label attributes
Focus management – Logical focus order
Screen reader-friendly – Semantic HTML structure
High contrast – Takes account of the system’s colour settings
Touch-friendly – Large touch targets (at least 44px)
Best practice
- Always provide subtitles – even automatically generated subtitles are better than none at all
- Use descriptive captions – Help users identify the languages of the audio tracks
- Test on mobile devices – ensure the transcript is readable on small screens
- Consider positioning – Placing the transcript next to the video works well on desktop
- Keep the design consistent – Match the design to your website whilst ensuring good readability