LearnBuilding Custom Controls for HTML5 Videos


Matt West
writes on February 14, 2013

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!


Learning with Treehouse for only 30 minutes a day can teach you the skills needed to land the job that you've been dreaming about.

Get Started

35 Responses to “Building Custom Controls for HTML5 Videos”

  1. Marco Principia on February 12, 2018 at 8:18 am said:

    Sorry. I was unaware that ” ” are not allowed. So I just changed them in ‘ ‘ and everything is working fine.

  2. video::-webkit-media-controls-enclosure {
    display:none !important;

    /*.custom-video-controls {
    z-index: 2147483648;

    hide controls in fullscreen

  3. This is simply the best tutorial I have found ever to style Video player, good job! I like this website from now on.

  4. With Me the timeupdate was not working.
    In case this is your problem, here is the solution:
    video.addEventListener(“timeupdate”, function() {
    var value = video.duration * (progressBar.value/100);
    video.currentTime = value;

  5. Corey Duffel on December 26, 2015 at 6:49 am said:

    Whenever I try to drag the seek bar the media file just resets to zero. I have no problem getting the seek bar to update as the file plays. What could be causing this?

  6. [url=http://www.bestevance.com/RogerDubuis/index_3.html]プラダ スーパーコピー,プラダ 財布 コピー,プラダ 新作 財布ブランド財布コピー,ブランド スーパーコピー 財布,プラダ スーパーコピー 財布,シャネル財布コピー,グッチ スーパーコピー 財布,エルメス スーパーコピー 財布,ルイヴィトン長財布コピー,スーパーコピー財布,エルメスコピー財布,各種のブランドはかばんをコピーします偽物ブランド,激安偽物,ブランド財布コピー,エルメス財布コピー,ブランドのコピーブランド財布,ルイ?ヴィトンブランド財布コピー,偽ブランドグッチ財布,D&G,コピー財布偽物,偽物時計コピー,時計,ボッテガベルト,,靴,その他のバッグコピー,ブランド財布激安,ブランド激安販売,偽ブランド激安市場,通販送料無料專門店 ルイヴィトンコピー 児玉店,当店ルイヴィトン コピー 財布、ルイヴィトン コピー バッグ 全MAX80%OFF!期間限定SALE。最短即日発送。送料無料ルイヴィトン コピー,ルイヴィトン コピー 財布,ルイヴィトン コピー バッグ[/url]

  7. [url=http://www.bagkakaku.com/celine_bag.html]エルメス ボリードスーパーコピー.ブランド直営店.ブランド,エルメス激安通販,業界で最高な品質に挑戦します!”ブランドN級品ブランドコピー 代引き,スーパーコピー時計,ブランドN級品,楽天コピーブランド,,偽物ブラン日本最大級の最高のスーパーコピーブランド財布激安代引き販売店,スーパーコピー時計の激安老舗.!国内No.1時計コピー工房,アフターサービスも自ら製造したスーパーコピー時計なので、技術力でお客様に安心のサポー トをご提供させて頂きます。スーパーコピー 代引きN品をご 購入の方は、こちらへ.弊社は正規品と同等品質のコピー品を低価で お客様に提供します!すべての商品は品質2年無料保証です。100%実物写真ですし、品質が完璧です!”スーパーコピーブランド財布激安 偽物財布激安コピー ルイヴィトン財布偽物,偽物財布コピー[/url]

  8. [url=http://www.brandiwc.com/brand-62-copy-0.html]財布コピー、バッグコピー、腕時計コピー、ベルトコピー靴コピーネックレスコピー、手帳コピー、小物コピー、SS品、N品、価格激安、品質の保証,2015人気ブランド偽物,歓迎光臨楽天★送料無料(日本全国)典雅気質!シャネルバッグCHH67723(*^^*)11月シャネル手作り新作(*^^*)時流の先端快適美品!シャネルブーツCH783283四季向け「 シャネル靴」最高な選択!ブランドコピー 代引きコピーブランド 代引きスーパーコピー 代引きスーパーコピーブランドバッグルイヴィトン コピーシャネル コピー[/url]

  9. [url=http://www.ooobag.com/index.html]弊社は海外安心と信頼のプラダ 時計 コピーです。2015 新作が満載!皆様を歓迎して当店をご光臨賜ります。ロレックス時計コピー,パネライ時計コピー,ウブロ時計コピー ,ブライトリング時計コピー,IWC時計コピー,フランクミュラー時 計コピー,ショパール時計コピー,フェラーリ時計コピー,グラハム 時計コピー,ハリー ウィンストン時計コピー等。サイトは世界一流ブランド コピー 専門店です。ぜひ一度当店の商品をお試しください。驚きと満足を保証致します。ご利用をお待ちしております。[/url]

  10. [url=http://www.msnbrand.com/brand-copy-IP-12.html]2015ブランド財布コピールイヴィトン財布コピー,シャネル財布コピー,グッチ財布コピー,エルメス財布コピークロエ財布コピー,ブラダ財布コピー,ブルガリ財布コピー,ドルチェ&ガッバ―ナ財布コピーバレンシアガ財布コピー,ボッテガ.ヴェネタ財布コピーロレックス時計コピー,ブルガリ時計コピー,フランク ミュラー時計コピーシャネル時計コピー,カルティエ時計コピー_オメガ時計コピー,IWC時計コピールイヴィトン時計コピー,オーデマ ピゲ時計コピー,ブライトリング時計コピーコピーブランド、ブランド激安、人気ブランドの販売、通販、オークション、新作のスーパーコピーブランドコピー、韓国スーパーコピー、ブランド激安、偽物ブランド、ブランドバッグ、激安かばん、ルイヴィトン偽物、財布激安.商品は全く写真の通りです。[/url]

  11. [url=http://www.brandiwc.com/brand-3-copy-0.html]最も美しいスーパーコピー,超格安ブランド時計コピー激安通販専門店!ブランド品に憧れて、予算オーバーし、諦めなければならないことがありましたか。スーパーコピー品が一番いいチョイスだ思います。少しのお金でも、世界中一番人気を持つブランド品、貴族しか買えない贅沢品がゲットできます。素敵な外観と実用性に優れたブランド コピー バッグ,,スーパーコピー財布,スーパーコピー 代引き,エルメス コピー,ルイヴィトン 財布、ルイヴィトン バッグ、ベルトなどの逸品はお客様に提供します。誰でもブランド品を手に入れられるのは弊社の経営理念です。当店の最大目標はお客様が安心してお買い物が出来き、お客様の頼りになるお店を目指す事ことです。お洒落な貴方はきっとこのチャンスを見逃しなくよ![/url]

  12. [url=http://www.gginza.com/bag/prada/index_4.html]スーパーコピーブランド格安販売店はこちらへ!品々の激安価格に持ったスーパーコピーブランド 代引きの新作はお客様に提供されます。安心、迅速、確実、お客様の手元にお届け致します。★弊社は9年の豊富な経験と実績を持っております。★一流の素材を選択し、精巧な作り方でまるで本物のようなな製品を造ります。★品質を重視、納期も厳守、お客様第一主義を貫きは当社の方針です。★驚きの低価格で商品をお客様に提供致します!★早速に購入へようこそ![/url]

  13. Hey Matt,

    could you explain how to attach current time and duration to this?

    I have used your method as a complete newbie and have a decent looknig player, so thankyou!
    The time and duration would be the icing on the cake!


  14. Hi Matt:
    Got a question. How do I adjust the size of the start button to a smaller size on the player view window when th video first loads up.

  15. Nice tutorial!

  16. You could certainly see your expertise within the paintings you write. The world hopes for even more passionate writers such as you who aren’t afraid to say how they believe. All the time follow your heart.

  17. 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.

  18. kiran on July 4, 2013 at 7:54 am said:

    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

  19. Barry on July 3, 2013 at 5:51 am said:

    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?

  20. Jonathan on June 27, 2013 at 7:00 am said:

    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!

  21. 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?

  22. Christian on June 19, 2013 at 5:27 am said:

    Who is the frog on the picture? I want him as wallpaper 🙂

  23. darren on June 8, 2013 at 4:08 pm said:

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

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


    this might work for you.

  24. Unfortunately there’s no way I know of to override the native controls when in fullscreen mode.

  25. oblique on April 14, 2013 at 10:18 am said:

    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

  26. 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 !

  27. Thanks Matt 🙂 This helped a lot 🙂

Leave a Reply

You must be logged in to post a comment.

man working on his laptop

Are you ready to start learning?

Learning with Treehouse for only 30 minutes a day can teach you the skills needed to land the job that you've been dreaming about.

Start a Free Trial
woman working on her laptop