Building HTML5 video controls with JavaScript

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

The HTML5 video ele­ment is now includ­ed in Fire­fox, Safari & Chrome, and on its way in Opera. By using JavaScript to access the media ele­ments API it’s easy to build your own cus­tom con­trols for it; in this arti­cle I’m going to show how I built a (very) basic con­trol interface.

A quick dis­claimer: my JavaScript is a lit­tle rusty, so may not use best prac­tice through­out; if you can see a way my code could be bet­ter, don’t hes­i­tate to let me know.

Any­way, here’s the fin­ished demo.

Getting started

First you must include the video ele­ment. There are a num­ber of attrib­ut­es avail­able, but for our pur­pos­es we need define only the src, which is the URI of our video file Update: changed the markup to use the more cor­rect source ele­ments inside video.

<video>
  <source src="filename.mp4">
  <source src="filename.webm">
  <source src="filename.ogg">
</video>

The video has been encod­ed twice, once in The­o­ra and once in H264, to cater for dif­fer­ent browsers; Kroc Camen’s Video for Every­body explains the rea­sons behind this (and how to make a bul­let­proof play­er). Update: added WebM support.

Hav­ing marked up a few con­trols with HTML (I’ve used id attrib­ut­es on all of them to make this demo eas­i­er), the next step is to write the JavaScript to access the API (which is well explained in this arti­cle at the Mozil­la Devel­op­er Cen­ter) for the controls.

The first and most impor­tant con­trol is the play/pause but­ton; for this I’ve writ­ten a func­tion which checks so see if the paused attribute is true or false, and trig­gers the play() or pause() meth­ods accordingly:

play.addEventListener('click',playControl,false);
function playControl() {
    if (video.paused == false) {
        video.pause();
        this.firstChild.nodeValue = 'Play';
        pauseCount();
    } else {
        video.play();
        this.firstChild.nodeValue = 'Pause';
        startCount();
    }
}

You’ll notice that it also updates the con­trol text to indi­cate the action that the con­trol will per­form. There are also two func­tion calls — pauseCount() and startCount() — which con­trol the timer shown next to the play button.

The timer uses the currentTime and duration attrib­ut­es (although the lat­ter does­n’t seem to be cur­rent­ly sup­port­ed by Chrome). To get the cur­rent time I’ve used setInterval to cre­ate a loop:

function startCount() {
    t = window.setInterval(function() {
        if (video.ended != true) {
            timer.firstChild.nodeValue = Math.round(video.currentTime + 1);
        } else {
            play.firstChild.nodeValue = 'Play';
            window.clearInterval(t);
        }
    },1000);		
}

First it uses an if...else state­ment on the ended attribute to check that the video has not fin­ished play­ing; if it has­n’t, it updates the timer with currentTime (plus a lit­tle maths). If the video HAS fin­ished, it uses clearInterval to stop the loop; this is also used in a func­tion to pause the timer if the pause con­trol is used:

function pauseCount() {
    window.clearInterval(t);
}

To com­plete the con­trols we have func­tions to increase and decrease the vol­ume. Both are very similar:

vUp.addEventListener('click',volUp,false);
function volUp() {
    if (video.volume  1) {
        video.volume = Math.round((video.volume + 0.1)*10)/10;
        volume.firstChild.nodeValue = Math.round(video.volume*10);
    }
}

First they check that the minimum/maximum lim­its have not been reached, and increase/decrease the volume attribute if not. Vol­ume is on a scale of 0 to 1, and this func­tion changes that val­ue in incre­ments of 0.1. The on-screen vol­ume counter is also changed accordingly.

There are a num­ber of small details else­where in the script, so feel free to have a dig through to see what else I’ve done; here’s anoth­er link to the fin­ished demo.

Further steps

I’ve obvi­ous­ly used a lit­tle CSS to tidy the con­trols up, but a lot more could be done; using images instead of text, for exam­ple, or per­haps using some­thing like jQuery’s user inter­face library to make more dynam­ic controls.

This arti­cle was intend­ed only to show how easy it is to get start­ed; what will be excit­ing is to see how these tech­niques can be expand­ed upon.

Update: If you found this arti­cle use­ful, you may be inter­est­ed to know that I returned to this sub­ject in a lat­er post, Build­ing a bet­ter HTML5 video play­er with Glow.

15 comments on
“Building HTML5 video controls with JavaScript”

  1. Hey I have a play­er in BETA and I still have prob­lems with the seek­ing, how much has been played (buffer-bar, progress-time)

    Thanks.

    ps how do i do this?
    (video.duration ? video.currentTime) ? 100; /* = “1.0002151”; */

  2. Hi James, take a look at my fol­low-up tuto­r­i­al, Build­ing A Bet­ter HTML5 Video Play­er With Glow, for more infor­ma­tion about this.

    As for your sec­ond ques­tion, I’m not sure what the ques­tion marks mean in your exam­ple but if I under­stood it cor­rect­ly it looks like you want to use Math.Round():

    Math.round((video.duration ? video.currentTime) ? 100)

    Hope that helps.

  3. […] it might be inter­est­ing to me if I get deep­er into HTML5 espe­cial­ly by using the <video> tag. I’ve read it comes to live in com­bi­na­tion with […]

  4. Very thanks .. I like make my own apps =)

  5. […] year Peter Gasston wrote a post (Build­ing HTML5 video con­trols with JavaScript) intro­duc­ing the HTML5 Media Ele­ments API and demon­strat­ing a sim­ple set of con­trols for playing […]

  6. Bril­liant job Peter!!!

  7. I’m curi­ous if you have to have any spe­cif­ic AddTypes to the htac­cess file? I’m using the same video types on my project and I cant get the video to play in my Android 2.0 brows­er. When I go to to the demo how­ev­er linked on this page it plays fine.

    I have added ogv, webm and mv4 to my htac­cess and when I try to play my videos on my serv­er it says can­not play.

  8. i am try­ing to cre­ate a video play­er that i can watch live video and mark points of inter­est. How can i log a point of inter­est while video feed is com­ing in?

  9. In case that video is all­ready play­ing, what should i do to ini­cial­ize this cor­recly? Cur­rent­ly it will only work if i click play/pause…

    thanks

  10. How would one stop the video and start it again at the beginning?
    I don’t want to pause where it is, I want to reset the posi­tion to the beginning.

  11. hel­lo,
    This solu­tion does­n’t work with Fire­fox 11 but with Chrome, it works ;)
    help me please –’ 

    my code source : 

    play.addEventListener(‘click’,playControl,false);
    var video = document.getElementById(‘videohead’);

    func­tion playControl() {
    if (video.paused == false) {
    video.pause();
    document.getElementById(‘playpause’).src =’./images/play.png’;
    document.getElementById(‘li_playpause’).title = ‘Play’;
    }
    else {
    video.play();
    document.getElementById(‘playpause’).src=’./images/pause.png’;
    document.getElementById(‘li_playpause’).title = ‘Pause’;
    }
    }

  12. Actu­al­ly i’m fac­ing a bit of prob­lem in this i don’t real­ly know whats caus­ing this error..

  13. I have been asked to cre­ate a brand­ed video play­er for a UofT chil­drens ani­mat­ed book. I was giv­en a mock up with a play/stop but­ton, a mute but­ton and a vol­ume con­tols (all would be images in a car­toon-esque theme.
    How do I bind these but­tons with the play­ers func­tion­al­i­ty? Is there an exam­ple of this somewhere?
    Thanks,
    Luis

  14. very good job peter i am try­ing to cre­ate a video play­er that i can watch live video and mark points of interest.can i make a video play­er which ful­fill this

  15. @REM, It seems that fire­fox requires the prop­er­ties to be called as a func­tion for the video ele­ment. So basi­cal­ly if (video.paused == false) needs to be if (video.paused() == false) but sub­se­quent­ly, this breaks Chrome/Safari (most like­ly in the ren­der­ing engine Webkit).