Media Element
HTML5
The track element specifies text tracks for <video> and <audio> elements. It provides captions, subtitles, chapter titles, and audio descriptions in WebVTT format, making media content accessible to all users.
Interactive code playground requires JavaScript. Here's the code:
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"
type="video/mp4">
<track kind="captions"
src="/captions-en.vtt"
srclang="en"
label="English"
default>
<track kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Español">
</video>
<p>Click CC button to enable captions/subtitles</p>
< track kind = " captions " src = " captions.vtt " srclang = " en " label = " English " >
The <track> element is void (self-closing) and must be a child of <video> or <audio>.
Specifies what type of text track to display:
Value Purpose Use Case captionsTranscription and sound effects For deaf/hard of hearing users subtitlesTranslation of dialogue For users who don’t understand the audio language descriptionsAudio descriptions of video For blind/low vision users chaptersChapter titles for navigation For quick navigation through media metadataMetadata for scripts Not visible to user, for JavaScript
Interactive code playground requires JavaScript. Here's the code:
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
type="video/mp4">
<!-- Captions: dialogue + sound effects -->
<track kind="captions"
src="/captions.vtt"
srclang="en"
label="English Captions"
default>
<!-- Subtitles: dialogue only -->
<track kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Spanish Subtitles">
<!-- Chapters for navigation -->
<track kind="chapters"
src="/chapters.vtt"
srclang="en"
label="Chapters">
</video>
URL of the track file (must be WebVTT format):
< track src = " captions.vtt " >
< track src = " https://example.com/subtitles.vtt " >
< track src = " /media/tracks/descriptions.vtt " >
Language of the track text (BCP 47 language tag):
< track srclang = " en " > <!-- English -->
< track srclang = " es " > <!-- Spanish -->
< track srclang = " fr " > <!-- French -->
< track srclang = " de " > <!-- German -->
< track srclang = " ja " > <!-- Japanese -->
< track srclang = " zh-CN " > <!-- Chinese (Simplified) -->
< track srclang = " pt-BR " > <!-- Portuguese (Brazil) -->
User-visible title for the track:
Interactive code playground requires JavaScript. Here's the code:
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4"
type="video/mp4">
<track kind="captions"
src="/captions-en.vtt"
srclang="en"
label="English">
<track kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Español">
<track kind="subtitles"
src="/subtitles-fr.vtt"
srclang="fr"
label="Français">
</video>
<p>Labels appear in the CC menu</p>
Enables the track by default if user preferences don’t indicate otherwise:
<!-- This track loads automatically -->
Attribute Required Description Example kindNo Type of text track captions, subtitles, descriptions, chapters, metadatasrcYes URL of track file (WebVTT) src="captions.vtt"srclangFor subtitles/captions Language code (BCP 47) srclang="en"labelFor subtitles/captions User-visible title label="English"defaultNo Enable by default default
00:00:00.000 --> 00:00:03.000
Welcome to our video tutorial.
00:00:03.000 --> 00:00:07.000
Today we'll learn about HTML5 video.
00:00:07.000 --> 00:00:11.000
00:00:00.000 --> 00:00:03.000
Welcome to our video tutorial.
00:00:03.000 --> 00:00:07.000
Today we'll learn about HTML5 video.
00:00:00.000 --> 00:00:03.000
<v Speaker1>Hello, how are you?</v>
00:00:03.000 --> 00:00:05.000
<v Speaker2>I'm doing great!</v>
00:00:05.000 --> 00:00:08.000
<c.important>Important announcement</c>
00:00:08.000 --> 00:00:11.000
<b>Bold text</b> and <i>italic text</i>
00:00:00.000 --> 00:00:03.000 align:start
00:00:03.000 --> 00:00:06.000 align:end
00:00:06.000 --> 00:00:09.000 position:50% align:middle
00:00:09.000 --> 00:00:12.000 line:0%
00:00:12.000 --> 00:00:15.000 line:100%
Transcription of dialogue plus sound effects for deaf/hard of hearing users:
00:00:00.000 --> 00:00:02.000
00:00:02.500 --> 00:00:05.000
<v Narrator>Welcome to our cooking show!</v>
00:00:05.500 --> 00:00:07.000
00:00:07.000 --> 00:00:10.000
<v Chef>Today we're making pasta.
00:00:10.500 --> 00:00:11.500
Note
Captions include all audio information (dialogue, music, sound effects), while subtitles only translate dialogue.
Translation of dialogue for users who understand the audio language:
00:00:02.500 --> 00:00:05.000
Bienvenido a nuestro programa de cocina!
00:00:07.000 --> 00:00:10.000
Audio descriptions for blind/low vision users:
00:00:00.000 --> 00:00:05.000
A chef enters a modern kitchen wearing a white apron.
00:00:10.000 --> 00:00:15.000
The chef places a pot of water on the stove.
00:00:20.000 --> 00:00:25.000
Steam rises as the water begins to boil.
Navigation markers for quick access to sections:
00:00:00.000 --> 00:01:30.000
00:01:30.000 --> 00:05:00.000
00:05:00.000 --> 00:15:00.000
00:15:00.000 --> 00:18:00.000
00:18:00.000 --> 00:20:00.000
Interactive code playground requires JavaScript. Here's the code:
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
type="video/mp4">
<!-- Note: Chapters appear in some browser's chapter menu -->
<track kind="chapters"
src="/chapters.vtt"
srclang="en"
label="Chapters">
</video>
<p>Some browsers show chapters in a menu for easy navigation</p>
Data for scripts, not displayed to users:
00:00:00.000 --> 00:00:10.000
{"products": ["apron", "pot"], "scene": "kitchen"}
00:00:10.000 --> 00:00:20.000
{"products": ["pasta", "sauce"], "scene": "cooking"}
Interactive code playground requires JavaScript. Here's the code:
<video id="meta-video" controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"
type="video/mp4">
<track kind="metadata"
src="/metadata.vtt"
srclang="en"
label="Metadata">
</video>
<div id="meta-output">Metadata will appear here</div>
<script>
const video = document.getElementById('meta-video');
const output = document.getElementById('meta-output');
video.textTracks[0].addEventListener('cuechange', (e) => {
const track = e.target;
if (track.activeCues && track.activeCues.length > 0) {
const cue = track.activeCues[0];
output.textContent = 'Current metadata: ' + cue.text;
}
});
</script>
Interactive code playground requires JavaScript. Here's the code:
<video id="api-video" controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
type="video/mp4">
<track kind="captions"
src="/captions-en.vtt"
srclang="en"
label="English">
<track kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Spanish">
</video>
<div id="track-info"></div>
<script>
const video = document.getElementById('api-video');
const info = document.getElementById('track-info');
// List all tracks
let html = '<h4>Available Tracks:</h4><ul>';
for (let i = 0; i < video.textTracks.length; i++) {
const track = video.textTracks[i];
html += '<li>' + track.kind + ': ' + track.label + ' (' + track.language + ')</li>';
}
html += '</ul>';
info.innerHTML = html;
</script>
Interactive code playground requires JavaScript. Here's the code:
<video id="control-video" controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4"
type="video/mp4">
<track id="en-track" kind="captions"
src="/captions-en.vtt"
srclang="en"
label="English">
<track id="es-track" kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Spanish">
</video>
<div>
<button onclick="enableTrack(0)">Enable English</button>
<button onclick="enableTrack(1)">Enable Spanish</button>
<button onclick="disableAll()">Disable All</button>
</div>
<script>
const video = document.getElementById('control-video');
function enableTrack(index) {
// Disable all tracks first
for (let i = 0; i < video.textTracks.length; i++) {
video.textTracks[i].mode = 'disabled';
}
// Enable selected track
video.textTracks[index].mode = 'showing';
}
function disableAll() {
for (let i = 0; i < video.textTracks.length; i++) {
video.textTracks[i].mode = 'disabled';
}
}
</script>
Mode Description disabledTrack not active (default) hiddenTrack active but not displayed (useful for metadata) showingTrack active and displayed
Interactive code playground requires JavaScript. Here's the code:
<video id="cue-video" controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
type="video/mp4">
<track kind="captions"
src="/captions.vtt"
srclang="en"
label="English"
default>
</video>
<div id="current-cue"
style="border: 2px solid #3b82f6; padding: 1rem; margin-top: 1rem; min-height: 50px;">
Current caption will appear here
</div>
<script>
const video = document.getElementById('cue-video');
const cueDisplay = document.getElementById('current-cue');
video.textTracks[0].addEventListener('cuechange', () => {
const track = video.textTracks[0];
if (track.activeCues && track.activeCues.length > 0) {
cueDisplay.textContent = track.activeCues[0].text;
} else {
cueDisplay.textContent = 'Current caption will appear here';
}
});
// Enable track
video.textTracks[0].mode = 'showing';
</script>
Level A Requirements:
Captions for all prerecorded audio content in video
Audio descriptions OR full text alternative for prerecorded video
Level AA Requirements:
Captions for all live audio content
Audio descriptions for all prerecorded video
Level AAA Requirements:
Sign language interpretation
Extended audio descriptions
00:00:00.000 --> 00:00:03.000
00:00:03.000 --> 00:00:06.000
<v John>Hello, welcome to the show!</v>
00:00:06.500 --> 00:00:08.000
00:00:09.000 --> 00:00:12.000
<v Sarah>Thanks for having me.
00:00:00.000 --> 00:00:03.000
00:00:03.000 --> 00:00:06.000
Hello, welcome to the show!
00:00:09.000 --> 00:00:12.000
Guidelines:
Include speaker identification
Describe non-speech sounds in [brackets]
Keep lines short (32-40 characters max)
Display for 1-7 seconds based on reading speed
Synchronize accurately with audio
Use proper punctuation and capitalization
Interactive code playground requires JavaScript. Here's the code:
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4"
type="video/mp4">
<!-- English captions (default) -->
<track kind="captions"
src="/captions-en.vtt"
srclang="en"
label="English"
default>
<!-- Spanish subtitles -->
<track kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Español">
<!-- French subtitles -->
<track kind="subtitles"
src="/subtitles-fr.vtt"
srclang="fr"
label="Français">
<!-- German subtitles -->
<track kind="subtitles"
src="/subtitles-de.vtt"
srclang="de"
label="Deutsch">
</video>
<p>Multiple language options appear in CC menu</p>
Interactive code playground requires JavaScript. Here's the code:
<style>
video::cue {
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
font-size: 1.2rem;
font-family: Arial, sans-serif;
}
/* Style speaker voices */
video::cue(v[voice="John"]) {
color: #3b82f6;
}
video::cue(v[voice="Sarah"]) {
color: #ec4899;
}
/* Style important captions */
video::cue(.important) {
color: #fbbf24;
font-weight: bold;
}
</style>
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"
type="video/mp4">
<track kind="captions"
src="/styled-captions.vtt"
srclang="en"
label="English"
default>
</video>
background-color : rgba ( 0 , 0 , 0 , 0.8 );
font-family : Arial , sans-serif ;
text-decoration : underline ;
text-shadow : 1 px 1 px 2 px black ;
Interactive code playground requires JavaScript. Here's the code:
<figure>
<figcaption>
<strong>Video Tutorial: HTML Basics</strong>
</figcaption>
<video controls width="640" height="360"
poster="https://peach.blender.org/wp-content/uploads/title_anouncement.jpg?x11217">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
type="video/mp4">
<!-- Captions for deaf/hard of hearing -->
<track kind="captions"
src="/captions-en.vtt"
srclang="en"
label="English Captions"
default>
<!-- Subtitles for translation -->
<track kind="subtitles"
src="/subtitles-es.vtt"
srclang="es"
label="Spanish Subtitles">
<!-- Audio descriptions for blind users -->
<track kind="descriptions"
src="/descriptions-en.vtt"
srclang="en"
label="Audio Descriptions">
<!-- Chapters for navigation -->
<track kind="chapters"
src="/chapters-en.vtt"
srclang="en"
label="Chapters">
Your browser doesn't support video.
</video>
<details>
<summary>Video Transcript</summary>
<p>[Full text transcript would go here...]</p>
</details>
</figure>
Interactive code playground requires JavaScript. Here's the code:
<video controls width="640" height="360">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
type="video/mp4">
<track kind="chapters"
src="/tutorial-chapters.vtt"
srclang="en"
label="Tutorial Sections">
<track kind="captions"
src="/tutorial-captions.vtt"
srclang="en"
label="English"
default>
</video>
<nav id="chapter-nav" style="margin-top: 1rem;"></nav>
<script>
const video = document.querySelector('video');
const nav = document.getElementById('chapter-nav');
video.textTracks[0].addEventListener('load', function() {
const track = this;
let html = '<h4>Jump to Section:</h4>';
for (let i = 0; i < track.cues.length; i++) {
const cue = track.cues[i];
html += '<button onclick="jumpToTime(' + cue.startTime + ')">' +
cue.text + '</button> ';
}
nav.innerHTML = html;
});
function jumpToTime(time) {
video.currentTime = time;
video.play();
}
</script>
Track files must respect CORS when loaded from different origins:
<!-- Video and track from same origin: works -->
< video controls src = " /video.mp4 " >
< track src = " /captions.vtt " >
<!-- Cross-origin: requires CORS headers -->
< video controls crossorigin = " anonymous "
src = " https://cdn.example.com/video.mp4 " >
< track src = " https://cdn.example.com/captions.vtt " >
Server configuration needed:
Access-Control-Allow-Origin: *
Content-Type: text/vtt; charset=utf-8
Feature Chrome Firefox Safari Edge <track> basic23+ 31+ 6+ 12+ WebVTT format 23+ 31+ 6+ 12+ kind="captions"23+ 31+ 6+ 12+ kind="subtitles"23+ 31+ 6+ 12+ kind="chapters"23+ 31+ 6+ 12+ kind="descriptions"51+ 55+ 12.1+ 79+ TextTrack API 23+ 31+ 6+ 12+ CSS ::cue 23+ 55+ 6+ 79+
YouTube Auto-Captions (free, requires editing)
Rev.com (professional human captions)
3Play Media (professional service)