Building Custom Controls for HTML5 Videos

custom-video-controls

One of my favorite things about HTML5 video is how easy it is to create your own custom controls. This not only allows you to style the controls however you would like but also allows you to add new controls like fast-forward or rewind. This is all done through the use of a JavaScript API.

In this post you are going to learn how to build your own custom controls for HTML5 videos.

Lets get started!

You can download a copy of all the assets used in this blog post here.


NOTE: A few weeks ago I wrote a post that covered how to get started with HTML5 video. If you haven’t used HTML5 video before I would recommend that you give that post a read first. Go ahead, I’ll wait.


Setting up your HTML5 Video

The first thing you need to do is write some HTML for your video and the controls. In the spirit of being truly cutting edge I’ve opted to use range inputs for the sliders but just be aware that these are not supported in all browsers yet.

You can download the video files and a stylesheet for this demo here.

<div id="video-container">
  <!-- Video -->
  <video id="video" width="640" height="365">
    <source src="videos/mikethefrog.webm" type="video/webm">
    <source src="videos/mikethefrog.ogv" type="video/ogv">
    <source src="videos/mikethefrog.mp4" type="video/mp4">
    <p>
      Your browser doesn't support HTML5 video.
      <a href="videos/mikethefrog.mp4">Download</a> the video instead.
    </p>
  </video>
  <!-- Video Controls -->
  <div id="video-controls">
    <button type="button" id="play-pause">Play</button>
    <input type="range" id="seek-bar" value="0">
    <button type="button" id="mute">Mute</button>
    <input type="range" id="volume-bar" min="0" max="1" step="0.1" value="1">
    <button type="button" id="full-screen">Full-Screen</button>
  </div>
</div>

Here you have created play/pause, mute and full screen buttons as well as two sliders. One that will be used to skip through the video and another to control the volume.

That’s all the HTML that you are going to need to get things working. If you view this in a web browser you should see the video on the page. When you hover over the video with your mouse cursor the controls should appear, as shown in the figure below. This hover effect is achieved using CSS and CSS3 transitions.

Custom Video Controls

Custom Video Controls

Setting up the JavaScript

Lets dive into writing the JavaScript that will bring your video controls to life.

Create a new JavaScript file called script.js and link it up to your HTML page using a <script> element.

<script src="script.js"></script>

Now open up this JavaScript file and add the following code to it.

window.onload = function() {

  // Video
  var video = document.getElementById("video");

  // Buttons
  var playButton = document.getElementById("play-pause");
  var muteButton = document.getElementById("mute");
  var fullScreenButton = document.getElementById("full-screen");

  // Sliders
  var seekBar = document.getElementById("seek-bar");
  var volumeBar = document.getElementById("volume-bar");

}

Here you have created a number of variables and initialized them with the video and controls from your HTML markup.

Hooking up the Play/Pause Button

The first video control we are going to tackle is the play/pause button. To get this working you will need to set up an event listener that checks whether the video is currently playing and then toggles playback appropriately. You can check the paused property of your video to examine the current playback state. Use the play() and pause() functions to control playback.

// Event listener for the play/pause button
playButton.addEventListener("click", function() {
  if (video.paused == true) {
    // Play the video
    video.play();

    // Update the button text to 'Pause'
    playButton.innerHTML = "Pause";
  } else {
    // Pause the video
    video.pause();

    // Update the button text to 'Play'
    playButton.innerHTML = "Play";
  }
});

Here you have set up an event listener for the click event on your play/pause button and used an if statement to toggle the video playback. You’ve also added some code that will update the text displayed on the button.

Hooking up the Mute Button

To get the mute button working you need to follow a similar process to the one you used for the play/pause button. This time however you need to examine the muted property of the video and toggle its value appropriately.

// Event listener for the mute button
muteButton.addEventListener("click", function() {
  if (video.muted == false) {
    // Mute the video
    video.muted = true;

    // Update the button text
    muteButton.innerHTML = "Unmute";
  } else {
    // Unmute the video
    video.muted = false;

    // Update the button text
    muteButton.innerHTML = "Mute";
  }
});

When the mute button is clicked this event listener will toggle the value of the muted property. You have also added some code that will update the button text.

Kicking it Full-Screen

Many modern web browsers have implemented a FullScreen API that allows you to give full screen focus to certain HTML elements. This is really great for displaying interactive media like videos in a fully immersive environment.

To get the full screen button working you need to set up another event listener that will call the requestFullScreen() function when the button is clicked. To ensure that this will work across all supported browsers you are also going to need to check to see if the requestFullScreen() is available and fallback to the vendor prefixed versions (mozRequestFullScreen and webkitRequestFullscreen) if it is not.

// Event listener for the full-screen button
fullScreenButton.addEventListener("click", function() {
  if (video.requestFullscreen) {
    video.requestFullscreen();
  } else if (video.mozRequestFullScreen) {
    video.mozRequestFullScreen(); // Firefox
  } else if (video.webkitRequestFullscreen) {
    video.webkitRequestFullscreen(); // Chrome and Safari
  }
});

Now if you reload the page and click the full screen button it should launch the video into full screen view. Pretty neat.

Hooking up the Seek Bar

That’s all the buttons sorted. Now lets take a look at that seek bar. This one gets a little more complicated so we’re going to approach it in three phases.

To start with lets hook it up so that dragging the slider handle changes the position in the video. To do this you need to set up an event listener on the seekBar that will execute when the change event is fired. You then need to calculate the time in the video that playback should be skipped to and update the time of the video accordingly.

// Event listener for the seek bar
seekBar.addEventListener("change", function() {
  // Calculate the new time
  var time = video.duration * (seekBar.value / 100);

  // Update the video time
  video.currentTime = time;
});

Here you have calculated the time by taking the total duration of the video (accessed using the duration property) and multiplying that by the value of the seekBar divided by 100. To update the position in the video you set the currentTime property of the video to the time you just calculated.

This basic implementation works but you might have noticed that the position of the slider handle doesn’t move as the video plays. To fix this you need to set up an event listener on the video that executes when the timeupdate event is fired. You then reverse the calculation that was used previously in order to get the value that the seekBar should be set to. The timeupdate event is fired continuously as the video plays.

// Update the seek bar as the video plays
video.addEventListener("timeupdate", function() {
  // Calculate the slider value
  var value = (100 / video.duration) * video.currentTime;

  // Update the slider value
  seekBar.value = value;
});

Now if you reload the page and start the video you should see that the slider handle moves along as the video plays!

There’s just one more bug that we need to fix with the seek bar. If you slowly drag the slider handle you will notice that the video keeps trying to play, resulting in a stuttering playback. To fix this you need to pause the video when the slider handle starts to be dragged and then play it again once the handle is dropped. You can do this by using two event listeners that execute when the mousedown and mouseup events are fired. Pause the video on mousedown and play it again on mouseup.

// Pause the video when the slider handle is being dragged
seekBar.addEventListener("mousedown", function() {
  video.pause();
});

// Play the video when the slider handle is dropped
seekBar.addEventListener("mouseup", function() {
  video.play();
});

Hooking up the Volume Control

The final control to implement is the volume slider. For this you need to set up an event listener for the change event. When this event fires you just need to take the value from the slider and use it to update the value of the volume property on the video.

The volume property should always have a value between 0 and 1. If you look back at your HTML markup you can see that we used the min and max attributes on the volume input to enforce this requirement.

// Event listener for the volume bar
volumeBar.addEventListener("change", function() {
  // Update the video volume
  video.volume = volumeBar.value;
});

That’s it! Congratulations, you just created your very own controls for a HTML5 video.

HTML5 video opens up a lot of cool new opportunities for developers. Being able to easily create your own custom controls is just one of them. Take a look at some of the demos on HTML5Rocks for inspirational on where you can go from here.

If you build some cool looking controls for your videos post a link in the comments below. It would be awesome to see them!

Comments

16 comments on “Building Custom Controls for HTML5 Videos

  1. There is an issue with slide bars. Even with your download file, the input tag still appear normaly and not as a slider. Could you help me please ? I realy woud like to use your work wich is pretty good !

  2. Thanks for this it works well in Safari and Chrome. I mamaged to customise it to my needs. BUT I get a problem in Firefox (20.0) the seek bar and the volume bar appear as a numerical readout.

    Any suggestions on how to fix this would be very appreciated. It’s such a bonus to have this control over the playback controls that are ugly in most browsers. Thanks

  3. // this part of the script is to remove native controls

    var video = document.getElementsByTagName(‘video’)[0];

    video.removeAttribute(‘controls’);

    this might work for you.

  4. Very usefull! just one question…if i have more than one video in a page, how can i have the controls for all of them?

    • You could use Javascript to add the markup for the custom controls by selecting all video elements and injecting that code to all of them.

  5. Hi Matt,

    First off, absolutely excellent tutorial that covers a wide range of techniques that I was looking for. I am working on a custom button and function for my site that should hopefully place a reduced opacity image over the top of the frame and make this function as a button, both playing the video and making it fullscreen at the same time.

    I have go so far as to make it look exactly like I want but the function just doesn’t seem to work, would you possibly be able to help with this? If you can find time/would like to, that would be greatly appreciated!

  6. Is there a way to hijack the requestFullscreen command so it uses a size of 1024×768? Alternatively can we add a new button that will allow the video to be displayed at 1024×768?

  7. i am using ur code, but not able to find seekbar in firefox browsers…
    As u have said i looked up with the jquery-ui slider but exactly i don no how to implement it in ur code.. pls suggest

  8. Hi Matt.
    This is a great tutorial and exactly what I’ve been looking for. Can you suggest changes necessary for the javascript if I have more than one video to show on a page? Thank you for any help.