Building a better HTML5 video player with Glow

Warning This article was written over six months ago, and may contain outdated information.

Last year I wrote a post (Building HTML5 video controls with JavaScript) introducing the HTML5 Media Elements API and demonstrating a simple set of controls for playing video.

In this (somewhat belated) follow-up I’m going to explore building a more interactive set of controls using a JavaScript UI library; I’m going to use Glow, but it could easily be adapted to jQuery UI or similar.

You can see the player I’ll be using as an example here — although it must be stressed that it’s not a final version, for reasons I’ll cover at the end:

HTML5 & Glow Video Player

The markup

The video player itself is pretty straightforward:

<video autobuffer controls height="180" poster="BBB_poster.jpg" width="320"> 
  <source src="bbb.mp4" type="video/mp4">   
  <source src="bbb.webm" type="video/ogg">
  <source src="bbb.theora.ogg" type="video/ogg">
  <img alt="Film Poster" height="180" src="BBB_poster.jpg" width="320">

The video element has the controls attribute set, which we’ll remove with JavaScript later. Note also the poster attribute, which displays a still image until the video is ready to be played, at which point it displays the first frame instead.

Next there are two source elements, which serve the video to Firefox, Opera and Chrome (ogg) and Safari (mp4). Finally there’s an img element, which displays if the browser doesn’t have video support. Update: Added WebM support.

As for the controls, rather than list them here I’ll ask you to view the source to see what I’ve done. Basically I’ve added a bunch of form elements; two input image types for the play and volume icons, and two input text types for the duration and volume sliders. The latter two aren’t necessary, but I wanted them there for accessibility reasons.

The style

How I’ve styled the player doesn’t matter too much; I’ve been influenced by the Quicktime player for the layout of the controls, but really the CSS isn’t too important here. The only thing to note is that I’ve added some rules here for screen overlays, which I’ll explain in due course:

.overlay { background-repeat: no-repeat; height: 180px; position: absolute; width: 320px; }
.paused { background-color: rgba(0,0,0,0.2); background-image: url('pause.png'); background-position: left bottom; }
.play { background-image: url('play.png'); background-position: center center; }

The JavaScript

You can see all the script I’ve used in the file video.js. I’ll go through some of the more important functions in turn.

Setting up

The first thing I’ve done is removed the native controls from the player for people who have JS enabled, so as not to provide two conflicting sets of controls:

video[0].controls = false;

Next I’ve defined some of the key variables which I’ll be using throughout the script. One of those variables, volumeSlide, is assigned to one of Glow’s native widgets, a Slider; this will be used to control the volume:

volumeSlide = new glow.widgets.Slider('#volume',{bindTo:'#vol_count', buttons:false, step:0.1, min:0, max:1, size:70, val:1});

You can see what all the options do in the Glow documentation, but the key ones I’ve set are for it to appear in <div id=“volume”>, to have a minimum value of 0 and a max of 1, and to increment in steps of 0.1. This matches the volume setting for the video element.

Waiting for the metadata

For the next step I’m going to create another slider, but this time for the duration/seek bar. In order to do this, however, I need to query the video’s metadata to know what the duration of the video is, and in Safari (which uses mp4 video) that doesn’t load before the rest of my JS has run.

To get around this I’ll poll the readyState attribute every half a second — with the setInterval function — until it’s value is at least 1, which means the metadata has loaded; once that’s done, I’ll load the slider:

t = window.setInterval(function() {
  if (video[0].readyState >= 1) {
    durationSlide = new glow.widgets.Slider('#vid_duration',{bindTo:'#duration_count', buttons:false, step:1, min:1, max:Math.round(video[0].duration-1), size:260, val:0});

So you can see there that I’ve created the slider with a minimum value of 1 and a maximum of the duration of the video (in seconds), to increment in steps of 1. After that the setup is complete so I can begin the actual playback functions.

Playback controls

There are too many functions to go into in detail, so I’ll quickly go through what happens. First an overlay is placed over the top of the video, which begins playback when clicked. Next, event listeners are added to the play button, the volume icon, and the volume and duration sliders.

The listener on the play button runs the function playControl, which determines the state of playback (ended, paused or playing) and either plays or pauses the video accordingly. It also updates the icon to reflect its action (if it is paused, the icon changes to a play icon, and vice versa), and adds the pause overlay onto the video screen when relevant:

function playControl() {
  if (video[0].paused === true) {
    /* Further functions here */
} else if (video[0].ended === true) {
     /* Further functions here */
} else {
     /* Further functions here */

There’s a function called startCount which uses setInterval to move the duration slider along by one second while the video is playing, and a function called pauseCount which uses clearInterval to pause.

The muteToggle function does what you expect, and mutes the video; it also changes the volume icon to show that state, and disables the volume slider while it is active.

A further function, volumeIcons, sets the state of the volume icon; there are four possible icon states, which are used depending on the value of the volume.

And the last function, secondsToTime, converts second values into hour/minute/second values, allowing for the timer to be updated. This is done every second by the startCount function, and also used for the function which is called from the event listener on the duration slider.

That event is probably worth looking at in detail:,'slideStop',function(event){
  video[0].currentTime = event.currentVal;
  var currentSecs = secondsToTime(event.currentVal);
  vidTimer.text(currentSecs.h + ':' + currentSecs.m + ':' + currentSecs.s);

Using the slideStop event I can check when the slider has been moved, and first set the video to begin playback from that point, then update the timer with the same values. The volume slider has a similar event set on it.

Next steps

So as a reminder, here’s what I have so far:

HTML5 & Glow Video Player

Please bear in mind that this is very much a work in progress; I started writing the controls without Glow and introduced it at a later stage, so some of the JavaScript could do with being optimised.

The markup for the controls could also do with some extra work to make them fully accessible, which they probably aren’t right now. Also, all of the dimensions are built around this video size, and won’t scale if different sized videos are used.

I hope to return to this topic when I have more time, and create a robust set of video player controls which can be used in any site without extra work.

Please feel free to let me know if you encounter any bugs or oddities as you use this; it will help with the next stage of development.

11 comments on
“Building a better HTML5 video player with Glow”

  1. Hello Peter,
    how are you ?

    Perhaps you should have a look at

    Keep up the good work ;-)



  2. Hi Frankie,

    Yes, I’ve seen it, it’s a great project. Sublime is another similar project:

    But I like to play around on my own demo projects and see how it’s done :)

  3. […] 19. Building a better HTML5 video player with Glow […]

  4. […] This is a tutorial on building an HTML5 video player in Javascript. It’s meant to give you a basic understanding of the different options you have with the new video tag in HTML5, and the javascript needed to create some of the typical video controls you’d find in other players. 19. Building a better HTML5 video player with Glow […]

  5. […] 12. Tutorial – Building A Better HTML5 Video Player With Glow […]

  6. […] Building a better HTML5 video player with Glow […]

  7. […] 19. Building a better HTML5 video player with Glow […]

  8. […] Building a better HTML5 video player with Glow (Broken Links) […]

  9. […] Building a better HTML5 video player with Glow (Broken Links) […]

  10. Thanks Peter, my problem is now solved.

  11. […] Building a better HTML5 video player with Glow […]