Custom HTML Video Player With Playlist (Free Download)

Welcome to a tutorial and example on how to create a custom video player with a playlist. Want to build your own video player and add a playlist to it? Sadly, things are not that straightforward. There are no native implementations of a video playlist in HTML and Javascript. The only way to create a playlist is to build our own – Read on for an example!

 

 

TABLE OF CONTENTS

 

CUSTOM VIDEO PLAYER WITH PLAYLIST

All right, let us now get into the example of creating a custom video player with a playlist.

 

 

 

STEP 1) THE HTML

video.html
<div id="vWrap">
  <!-- (A) VIDEO TAG -->
  <video id="vVid"></video>
 
  <!-- (B) PLAY/PAUSE BUTTON -->
  <button id="vPlay" disabled><span id="vPlayIco" class="material-icons">
    play_arrow
  </span></button>
 
  <!-- (C) TIME -->
  <div id="vCron">
    <span id="vNow"></span> / <span id="vTime"></span>
  </div>
 
  <!-- (D) SEEK BAR -->
  <input id="vSeek" type="range" min="0" value="0" step="1" disabled>
 
  <!-- (E) VOLUME SLIDE -->
  <span id="vVolIco" class="material-icons">volume_up</span>
  <input id="vVolume" type="range" min="0" max="1" value="1" step="0.1" disabled>
 
  <!-- (F) PLAYLIST -->
  <div id="vList"></div>
</div>

There are 6 components for this custom video player.

  1. <video id="vVid"> The video tag itself.
  2. <button id="vPlay"> Play and pause button.
  3. <span id="vNow"></span> – The current playtime. <span id="vTime"></span> – Total time of the current video.
  4. <input id="vSeek"> Time seek slider bar, this is in seconds.
  5. <input id="vVolume"> Volume slider bar, this is a value from 0.0 (mute) to 1.0 (loudest).
  6. <div id="vList"> For the video playlist, we will use Javascript to generate it.

 

 

STEP 2) INITIALIZE VIDEO PLAYER

video.js
window.addEventListener("DOMContentLoaded", () => {
  // (A) PLAYER INIT
  // (A1) PLAYLIST - CHANGE TO YOUR OWN!
  let playlist = [
    {name: "Video A", src: "v1.mp4"},
    {name: "Video B", src: "v2.mp4"},
    {name: "Video C", src: "v3.mp4"}
  ];
 
  // (A2) VIDEO PLAYER & GET HTML CONTROLS
  const video = document.getElementById("vVid"),
        vPlay = document.getElementById("vPlay"),
        vPlayIco = document.getElementById("vPlayIco"),
        vNow = document.getElementById("vNow"),
        vTime = document.getElementById("vTime"),
        vSeek = document.getElementById("vSeek"),
        vVolume = document.getElementById("vVolume"),
        vVolIco = document.getElementById("vVolIco"),
        vList = document.getElementById("vList");
 
  // (A3) BUILD PLAYLIST
  for (let i in playlist) {
    let row = document.createElement("div");
    row.className = "vRow";
    row.innerHTML = playlist[i]["name"];
    row.addEventListener("click", () => vidPlay(i));
    playlist[i]["row"] = row;
    vList.appendChild(row);
  }
});
  • The first thing we do in Javascript is Captain Obvious. Wait until DOMContentLoaded before proceeding, make sure the HTML is done loading.
  • (A1) The playlist should be self-explanatory. Each video entry should have the track name name and source src.
  • (A2) Get all the HTML elements.
  • (A3) Loop through playlist to generate the HTML. Just take note that clicking on a track will trigger vidPlay().

 

STEP 3) PLAY MECHANISM

video.js
// (B) PLAY MECHANISM
// (B1) FLAGS
var vidNow = 0, // current video
    vidStart = false, // auto start next video
 
// (B2) PLAY SELECTED VIDEO
vidPlay = (idx, nostart) => {
  vidNow= idx;
  vidStart = nostart ? false : true;
  video.src = playlist[idx]["src"];
  for (let i in playlist) {
    if (i == idx) { playlist[i]["row"].classList.add("now"); }
    else { playlist[i]["row"].classList.remove("now"); }
  }
};
 
// (B3) AUTO START WHEN SUFFICIENTLY BUFFERED
video.addEventListener("canplay", () => { if (vidStart) {
  video.play();
  vidStart = false;
}});
 
// (B4) AUTOPLAY NEXT VIDEO IN THE PLAYLIST
video.addEventListener("ended", () => {
  vidNow++;
  if (vidNow >= playlist.length) { vidNow = 0; }
  vidPlay(vidNow);
});
 
// (B5) INIT SET FIRST VIDEO
vidPlay(0, true);
  • (B1) We use 2 flags to control the player.
    • vidNow keeps track of which video is currently playing in playlist.
    • vidStart will be used to control autoplay in (B3).
  • (B2) vidPlay() will play the selected video. For example, vidPlay(1) will play the second video in playlist. This works by setting video.src = playlist[N]["src"]. Again, take note of vidStart here.
  • (B3) Start playing once the current video is sufficiently buffered, but only if vidStart is set.
    • Basically, canplay can be triggered via 2 possible means. When we change video.src = NEW VIDEO, or upon recovering from a bad connection.
    • When the user has a bad Internet connection, we don’t want to force a patchy playback.
    • Thus the existence of vidStart, to make sure autoplay only applies after clicking on a playlist item (or when auto-starting the next video in the list).
  • (B4) When the current video ends, vidNow++ will play the next one.

 

 

STEP 4) PLAY/PAUSE BUTTON

video.js
// (C) PLAY/PAUSE BUTTON
// (C1) AUTO SET PLAY/PAUSE TEXT
video.addEventListener("play", () => vPlayIco.innerHTML = "pause");
video.addEventListener("pause", () => vPlayIco.innerHTML = "play_arrow");
 
 // (C2) CLICK TO PLAY/PAUSE
vPlay.addEventListener("click", () => {
  if (video.paused) { video.play(); }
  else { video.pause(); }
});
  • (C1) Automatically update the play/pause icon as the video play/pause. By the way, this is using Google’s Material Icons. Links below.
  • (C2) Click to play if the video is paused, click to pause if the video is playing.

 

STEP 5) TRACK TIME

video.js
// (D) TRACK PROGRESS
// (D1) SUPPORT FUNCTION - FORMAT HH:MM:SS
var timeString = secs => {
  // (D1-1) HOURS, MINUTES, SECONDS
  let ss = Math.floor(secs),
      hh = Math.floor(ss / 3600),
      mm = Math.floor((ss - (hh * 3600)) / 60);
  ss = ss - (hh * 3600) - (mm * 60);
 
  // (D1-2) RETURN FORMATTED TIME
  if (hh>0) { mm = mm<10 ? "0"+mm : mm; }
  ss = ss<10 ? "0"+ss : ss;
  return hh>0 ? `${hh}:${mm}:${ss}` : `${mm}:${ss}` ;
};
 
// (D2) INIT SET TRACK TIME
video.addEventListener("loadedmetadata", () => {
  vNow.innerHTML = timeString(0);
  vTime.innerHTML = timeString(video.duration);
});
 
// (D3) UPDATE TIME ON PLAYING
video.addEventListener("timeupdate", () => {
  vNow.innerHTML = timeString(video.currentTime);
});
  • (D1) In Javascript, the video has 2 very convenient properties – video.duration and video.currentTime. Problem is, they are in seconds. Thus we need a support function to format a “nice time string”.
  • (D2) Update the total playtime on receiving the metadata.
  • (D3) Update the current time while the video is playing.

 

 

 

STEP 6) TIME SEEK BAR

video.js
// (E) SEEK BAR
video.addEventListener("loadedmetadata", () => {
  // (E1) SET SEEK BAR MAX TIME
  vSeek.max = Math.floor(video.duration);
 
  // (E2) USER CHANGE SEEK BAR TIME
  var vSeeking = false; // user is now changing time
  vSeek.addEventListener("input", () => vSeeking = true); // prevents clash with (e3)
  vSeek.addEventListener("change", () => {
    video.currentTime = vSeek.value;
    if (!video.paused) { video.play(); }
    vSeeking = false;
  });

  // (E3) UPDATE SEEK BAR ON PLAYING
  video.addEventListener("timeupdate", () => {
    if (!vSeeking) { vSeek.value = Math.floor(video.currentTime); }
  });
});
  • (E1) Set the max time of the seek bar on receiving the video metadata.
  • (E2) Update video.currentTime when the user changes the seek bar.
  • (E3) Update the seek bar as the video plays.
  • (E2 & E3) The vSeeking flag is kind of confusing. But basically, we don’t want (E3) to update while the user is manually dragging the bar.

 

STEP 7) VOLUME

video.js
// (F) VOLUME
vVolIco.addEventListener("click", () => {
  video.volume = video.volume==0 ? 1 : 0 ;
  vVolume.value = video.volume;
  vVolIco.innerHTML = (vVolume.value==0 ? "volume_mute" : "volume_up");
});
vVolume.addEventListener("change", () => {
  video.volume = vVolume.value;
  vVolIco.innerHTML = (vVolume.value==0 ? "volume_mute" : "volume_up");
});

Self-explanatory.

 

 

STEP 8) ENABLE/DISABLE ALL CONTROLS

video.js
// (G) ENABLE/DISABLE CONTROLS
video.addEventListener("canplay", () => {
  vPlay.disabled = false;
  vVolume.disabled = false;
  vSeek.disabled = false;
});
video.addEventListener("waiting", () => {
  vPlay.disabled = true;
  vVolume.disabled = true;
  vSeek.disabled = true;
});

This final bit enables all controls when the player can play, and disables all controls while the player is still loading.

P.S. We can use canplaythrough to prevent “halfway breaks”, but the loading will take longer, depending on how large the video file is.

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

EXAMPLE CODE DOWNLOAD

Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

EXTRA BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

BACK/NEXT BUTTONS

I don’t see a need to add these buttons as there is already a playlist. But if you want to add them, here’s a simple Javascript snippet:

function backnext (n) {
  if (n) { vidNow++; } else { vidNow--; }
  if (vidNow >= playlist.length) { vidNow = 0; }
  if (vidNow < 0) { vidNow = playlist.length - 1; }
  vidPlay(vidNow);
}

 

MULTIPLE INSTANCES

Not impossible, but there are several design and technical issues.

  • Do you really need multiple playlist players on a single page?
  • Isn’t a single playlist easier to manage than multiple playlists?
  • So what happens when an instance is already playing? Pause that instance when the user clicks on another one?
  • Is playing multiple videos on the same page a good idea for mobile devices and slow connections?
  • Or track all the instances, and allow only one to play at a time? Isn’t this as good as a single instance?
  • How are you going to squeeze multiple players onto small screens? Good design idea?
  • A “single player with multiple different playlists” makes more sense.

So yep, feel free to challenge yourself if you really need “multiple instances”.

 

COMPATIBILITY CHECKS

This video player should work well across all “Grade A” modern browsers.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

12 thoughts on “Custom HTML Video Player With Playlist (Free Download)”

    1. Sorry, the security filter removed the code snippet. I don’t have half-eaten fruit devices to verify…

  1. Good morning,
    it’s possible remove all control and enable the autoplay?
    Sorry maybe for the stupid answer, but it’s is possible, I don’t understand how.

    Thanks

  2. Thanks.

    Can you make the list y-overflow scroll after say 6 entries ?
    (current implement is a space hog…)
    (Next and prev buttons would rock, but I don’t wanna push my luckl

  3. awesome, found your page on google search
    do you happen to know of a way to add a button somewhere to go to fullscreen mode (as well as from within fullscreen mode, go back to normal?)
    thanks for sharing your html/css/js code <3

    1. Thanks for this great code.
      I have things working, but regarding fullscreen, is it possible to do what youtube does with the fullscreen option?
      That is, make the current video fullscreen (not the page, which includes the playlist). This would be especially useful on phones.

Leave a Comment

Your email address will not be published. Required fields are marked *