How to Add Subtitles to an HTML5 Video (WebVTT Track Guide)
Browsers can show subtitles natively with no JavaScript library — you only need a WebVTT file and a <track> element.
Updated 2026-10-23
Step 1: Get a WebVTT file
If you only have SRT subtitles, convert them with the SRT to VTT converter. A minimal WebVTT file looks like this:
WEBVTT
00:00:01.000 --> 00:00:03.500
Hello, and welcome.
00:00:04.000 --> 00:00:06.000 line:10% align:center
This line is placed near the top.
The first line must be WEBVTT. Time stamps use a dot before the milliseconds. Save the file as UTF-8 with the extension .vtt.
Step 2: Add the track element
<video controls width="640" src="movie.mp4">
<track kind="subtitles" src="movie.en.vtt" srclang="en" label="English" default>
<track kind="subtitles" src="movie.es.vtt" srclang="es" label="Español">
</video>
kind: subtitles (translation), captions (includes sound descriptions), descriptions, chapters or metadata.srclang: a language code. Required forkind="subtitles".label: the name shown in the player’s menu.default: show this track unless the user chooses otherwise.
Step 3: Serve the file correctly
- Host the .vtt on the same origin as the page. If it comes from another domain, add the
crossoriginattribute to the video and allow the page with CORS headers (Access-Control-Allow-Origin). - Use the MIME type
text/vtt. - Test over HTTP(S). Opening the page from
file://prevents subtitles from loading in some browsers.
Styling the subtitles
Style the cues with the ::cue pseudo-element:
video::cue { font-size: 1.2rem; color: #fff; background: rgba(0,0,0,.6); }
video::cue(.yellow) { color: #ffd400; }
Inside the VTT file, mark a word with <c.yellow>warning</c> to apply the class. Browsers allow only a subset of CSS properties for cues (colour, background, font, text decoration, text shadow, outline), and native fullscreen on some mobile browsers uses its own styling.
Controlling tracks with JavaScript
const video = document.querySelector('video');
for (const t of video.textTracks) {
console.log(t.label, t.mode); // "disabled", "hidden" or "showing"
}
video.textTracks[0].mode = 'showing';
You can also listen to cuechange events to build interactive transcripts that highlight the current line.
Troubleshooting
| Problem | Check |
|---|---|
| Nothing appears | The file starts with WEBVTT, the path is correct, and the file is served via HTTP(S) with the right CORS setting. |
| Strange characters | Save as UTF-8; see the encoding fixer. |
| Subtitles are late or early | Shift with the timing shifter (it accepts VTT). |
| Cue is skipped | Each time line needs --> with spaces and a start earlier than the end. |
Accessibility notes
Use kind="captions" when the track includes sound descriptions for deaf and hard-of-hearing viewers, and provide a transcript where possible. Keep the guidelines for line length and reading speed in our timing guide.
A complete, copy-ready page
<!doctype html>
<html lang="en">
<body>
<video controls width="720" poster="poster.jpg">
<source src="movie.mp4" type="video/mp4">
<track kind="captions" src="movie.en.vtt" srclang="en" label="English (CC)" default>
<track kind="subtitles" src="movie.de.vtt" srclang="de" label="Deutsch">
</video>
</body>
</html>Other uses of text tracks
- Chapters: a track with
kind="chapters"contains cues whose text is the chapter title; players or your script can build a menu from it. - Descriptions: text descriptions of the visuals for blind users, read by a screen reader.
- Metadata: invisible cues carrying data (for example JSON) that your script reads in the
cuechangeevent to trigger on-page events.
Streaming (HLS and DASH)
For adaptive streaming, subtitles are usually delivered as segmented WebVTT referenced from the playlist. Packagers such as FFmpeg and Shaka Packager can create these from an SRT or VTT file, so keep a clean source file and let the packaging tool do the segmenting.
Tips for a good viewing experience
- Keep each cue within the limits in the timing guide; browsers do not reflow long lines nicely.
- Test in at least Chrome, Firefox and Safari, because the default cue styling and the caption menu differ.
- Provide a link to a plain-text transcript for people who cannot or prefer not to use captions.
Frequently asked questions
Can I use an SRT file directly in the track element?
No. Browsers support WebVTT only, so convert SRT to VTT first.
Does it work on mobile?
Yes, in modern mobile browsers. Fullscreen on iOS uses the system player, which has its own styling.
How do I offer several languages?
Add several track elements with different srclang and label values; the viewer picks one in the player’s caption menu.