how to dynamically change video.js videos and captions, with javascript


I am involved in a multidisciplinary data visualization research project. A part of it relies on qualitative data, namely video interviews. Regarding the videos, the Web designer wired the following layout:


Pretty neat and simple, isn’t it? The user clicks on one of the thumbnails below the video player. The thumbnail is marked as selected via a change of background-color of its container. The video player starts playing. On the right-side of the player, the quotes from the interview are displayed. They are actually outside the video-player. The code layout is simple, as well. It employs a series of HTML div and some new HTML5 tags such as video, source, and track.

Before jumping to the code, a disclaimer.

The code and style reported in this post were written during developing/exploration stages. They do not show a latest, polished code of quality. This holds especially true for the CSS parts

To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video

Video 1

The video names are numbered, e.g., 1.mp4, 2.mp4, etc. Same holds for the subtitles, and the thumbnails. Everything else is handled by the opensource video.js project. Now, the load of the first video works perfectly. On page load, video.js automatically finds the element, and it constructs the real video player by substituting the HTML5 tags with normal _div_s.

That was the issue for me. The project is a single landing page full of infographics. Users simply have to click on the thumbnail in order for the new video to load, play, and display the new quotes. No refresh of the page could be done.

Although Video.js APIs do offer ways for changing the video in the video player, there is no way to load the new captions/subtitles, as well. The source code suggested that such method did not exist. There was only a method to get the current subtitles.

One idea was to change the element on-the-fly right-before changing the player source file. Unfortunately, video.js needs the tags to be in place before loading the player object. In addition, once the player is loaded, the HTML5 tags are substituted with more normal divs.

Luckily, video.js provides a .dispose() method to destroy the player object. However, the method destroys the HTML5 code, too. There is a bug report about this issue. The issue was opened some months ago, and there are now some pull requests to sort it out.

Meanwhile, I needed a quick working solution. I found it. It is so simple that I am ashamed of how long it took me to find it out.

First of all, the contents of were removed from the HTML. Then, the following JavaScript was added.

var player;

function videoHTML(videoNumber) {
return '<video id="video-js" class="video-js vjs-default-skin" poster="img/' + videoNumber + '.jpg" preload="auto" controls="controls" width="600" height="300" data-setup="\'{&quot;example_option&quot;:true}\'">' +
'\t<source src="videos/' + videoNumber + '.mp4" type="video/mp4" /> \n' +
'\t\t<track id="video-srt" kind="captions" src="subs/' + videoNumber + '.srt" srclang="it" label="Italian" default="" />\n ' +
To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="" target="_blank">supports HTML5 video</a>
\n' +
'</video>'; } $("").click(function () { $("").css("background-color", "white"); $(this).css("background-color", "red"); var videoNumber = $(this).data("video"); player.dispose(); $('').html(videoHTML(videoNumber)); player = videojs('#video-js'); }); $(document).ready(function () { $('').html(videoHTML(1)); player = videojs('#video-js'); });

The function videoHTML simply returns the now deleted HTML5 part of the video player, adapted via the videoNumber parameter to load the desired set of video, captions, and thumbnails. The function is called with argument value 1 on page load (document ready), in order to load the first video. The global variable player will also contain the video player object.

Whenever the user clicks on a div.thumbnail, its related video number is gathered. The player gets destroyed. The HTML content is filled up with a fresh series of HTLM5 video tags through the videoHTML function. The player is recreated, so that it will use the new set of HTML5 tags related to the selected video.

That was it. I hope it will be of help.

As a bonus, I am sharing here the CSS code for putting the captions outside the video itself.

/* video container */
.video-background {
width: 600px;
height: 300px;
background-color: black;

/* captions/subtitles container */
.vjs-text-track-display {
position: absolute !important;
left: 600px !important;
top: 10px !important;
width: 600px;
display: block;
z-index: 10000000 !important;

/* actual captions/subtitles. The text can be styled here. */
.text-background {
width: 600px;
height: 300px;
background-color: black;

UPDATE: I added the whole sourcecode in a GitHub repository. The link is provided below. Feel free to inspect it.

I do not use a commenting system anymore, but I would be glad to read your feedback. Feel free to contact me.