Adding captions and subtitles

Working with HTML5 Video

Adding captions and subtitles

Working with HTML5 Video

  1. A basic HTML5 video
  2. Adding subtitles
  3. WebVTT syntax basics
  4. Building a custom menu with JavaScript
  5. Captions versus subtitles
  6. Cue settings
  7. Styling text cues
  8. Tags available to cues

A basic HTML5 video

A solid basis to start from

HTML5 video example

		  <video controls preload="metadata">
		      <source src="../video/sintel-short.mp4" type="video/mp4">
		      <source src="../video/sintel-short.webm" type="video/webm">

		      <p>It appears that your browser doesn't support HTML5 video.
		      Here's a <a href="../video/sintel-short.mp4">direct link to
		      the video instead</a>.</p>

Code time: tutorial start

Adding subtitles

<track> elements

		  <track label="English" kind="subtitles" srclang="en"
		    src="vtt/sintel-subtitles-en.vtt" default>
          <track label="Deutsch" kind="subtitles" srclang="de"
          <track label="Español" kind="subtitles" srclang="es"

<track> attributes

Code time: tutorial step 2

Cross browser UX not very good for track

You should therefore...

Implement a custom UI for <track> elements using JavaScript!

WebVTT syntax basics

WebVTT looks like so

          00:00:00.000 --> 00:00:12.000
          00:00:18.700 --> 00:00:21.500
          This blade has a dark past.

WebVTT syntax explanation

Implementing a custom subtitle menu

You can use whatever UI you want

We are using a select menu:

		    <select name="select">

Basic WebVTT API information

Code time: tutorial step 3

Set variables then hide all tracks

		  var video = document.querySelector('video');
          var select = document.querySelector('select');
          function hideTracks() {
            for (var i = 0; i < video.textTracks.length; i++) {
              video.textTracks[i].mode = 'hidden';

Build the select menu

		  var tracksOff = document.createElement('option');
          tracksOff.textContent = 'Tracks off';

Build the select menu

          for (var i = 0; i < video.textTracks.length; i++) {
            var curTrack = video.textTracks[i];
            var addTrackOpt = document.createElement('option');
            addTrackOpt.setAttribute('value',curTrack.kind + '-' + curTrack.language);
            addTrackOpt.textContent = curTrack.label + ' ' + curTrack.kind;

The select menu

Add an event listener

This runs the trackChange() function whenever the a new select value is selected

          select.addEventListener('change',function() {

The trackChange() function

          function trackChange(value) {
            if(value === 'off') {
            } else {
              var splitValue = value.split('-');
              for (var i = 0; i < video.textTracks.length; i++) {
                if(video.textTracks[i].kind === splitValue[0]) {
                  if(video.textTracks[i].language === splitValue[1]) {
                    video.textTracks[i].mode = 'showing';

How trackChange() works

Subtitles versus captions

Subtitles versus captions

Caption <track> example

          <track label="English" kind="captions" srclang="en"

Code time: tutorial step 4

Cue settings, tags and styling captions

WebVTT gets more complex

          00:00:18.700 --> 00:00:21.500 line:20% align:end
          <><b>Man</b>: This blade has a dark past.  </c>

Cue settings

Styling captions

Caption text cues have some special tags marking them up, stylable via CSS Extensions.

          <><b>Man</b>: This blade has a dark past.  </c>

Styling captions

The ::cue pseudo-element is the key to targetting text track cues for styling.

          video::cue { whitespace: pre; }
          video::cue(.man) { color:yellow }

What properties can be applied to text cues?

Available text cue tags

Adding a default selection

if(curTrack.language === 'en' && curTrack.kind === 'subtitles') {


Further resources

Getting involved with the MDN community


Fork me on Github