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">
      Your browser doesn't support HTML5 video.
      <a href="videos/mikethefrog.mp4">Download</a> the video instead.
  <!-- 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>

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;

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

    // 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) {
  } 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() {

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

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!