Build A Custom Video Player in HTML CSS & JavaScript

Build A Custom Video Player in HTML CSS & JavaScript Custom Video Player in JavaScript

Hey friends, today in this blog, you’ll learn to create a new project named Build A Custom Video Player in HTML CSS & JavaScript. Many viewers had frequently requested me to make this project. So, this time I’m going to create a custom video player in vanilla JavaScript.

Before starting this project, if you still didn’t view my previous video/blog on Custom Image Editor in JavaScript. You can go and watch it because many viewers have liked this video, and I believe you’ll like it too.

In this project (Custom Video Player in JavaScript), as you have seen in the preview image, this video player has many features like other video players. Such as play/pause, skip backward or forward, adjust volume and playback speed, picture in picture and fullscreen mode, etc.

If you’re curious about what this video player looks like, click here to view a live demo of this video player and if you want to see a demo or full video tutorial of this Custom Video Player in JavaScript, you can watch the given YouTube video.

Video Tutorial of Custom Video Player in JavaScript


In the above video, you’ve seen a demo of this custom video player and how I built it using HTML CSS & JavaScript. I hope you liked this video player and understood the basic codes and concepts behind creating this player.

If you’ve followed my JavaScript videos playlist or you’re familiar with JavaScript and have built some projects before like music player, range slider, todo list, etc. then you won’t have problems understanding the codes of this video player because I’ve tried my best to explain JavaScript codes by written comments.

But, if you’re new to JavaScript and didn’t build any projects before, this project’s codes will be complex for you to understand. So, I suggest you learn basic JavaScript and create some easy projects before making a custom video player.

If you liked this video player and want to get source codes or files, you can easily get them from the bottom of this page. I believe after watching the video, you can add more features to this video player and take this player to next level.

You might like this:

Custom Video Player in JavaScript [Source Codes]

To build a Custom Video Player using HTML CSS & JavaScript, you need to create three files: HTML, CSS & JavaScript file. Once you create these files, just paste the given codes into your file. If you don’t know how to create these files, where to paste the codes, or don’t want to do these, you can simply download the source code files of this Video Player by clicking on the given download button that is at the bottom of this page.

First, create an HTML file with the name index.html and paste the given codes into your HTML file. Remember, you’ve to create a file with a .html extension.

<!DOCTYPE html>
<!-- Coding By CodingNepal - -->
<html lang="en" dir="ltr">
    <meta charset="utf-8">
    <title>Custom Video Player in JavaScript | CodingNepal</title>
    <link rel="stylesheet" href="">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- These 3 links are only for icons -->
    <link rel="stylesheet" href="">
    <link rel="stylesheet" href=",wght,FILL,[email protected],100..700,0..1,-50..200" />
    <link rel="stylesheet" href="">
    <div class="container show-controls">
        <div class="wrapper">
            <div class="video-timeline">
                <div class="progress-area">
                    <div class="progress-bar"></div>
            <ul class="video-controls">
                <li class="options left">
                    <button class="volume"><i class="fa-solid fa-volume-high"></i></button>
                    <input type="range" min="0" max="1" step="any">
                    <div class="video-timer">
                        <p class="current-time">00:00</p>
                        <p class="separator"> / </p>
                        <p class="video-duration">00:00</p>
                <li class="options center">
                    <button class="skip-backward"><i class="fas fa-backward"></i></button>
                    <button class="play-pause"><i class="fas fa-play"></i></button>
                    <button class="skip-forward"><i class="fas fa-forward"></i></button>
                <li class="options right">
                    <div class="playback-content">
                        <button class="playback-speed"><span class="material-symbols-rounded">slow_motion_video</span></button>
                        <ul class="speed-options">
                            <li data-speed="2">2x</li>
                            <li data-speed="1.5">1.5x</li>
                            <li data-speed="1" class="active">Normal</li>
                            <li data-speed="0.75">0.75x</li>
                            <li data-speed="0.5">0.5x</li>
                    <button class="pic-in-pic"><span class="material-icons">picture_in_picture_alt</span></button>
                    <button class="fullscreen"><i class="fa-solid fa-expand"></i></button>
        <video src="demo-video.mp4"></video>

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


Second, create a CSS file with the name style.css and paste the given codes into your CSS file. Remember, you’ve to create a file with a .css extension.

/* Import Google font - Poppins */
@import url('[email protected];500;600&display=swap');
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;

  min-height: 100vh;
  background: #E3F2FD;

body, .container, .video-controls, .video-timer, .options
  display: flex;
  align-items: center;
  justify-content: center;

  width: 98%;
  user-select: none;
  overflow: hidden;
  max-width: 900px;
  border-radius: 5px;
  background: #000;
  aspect-ratio: 16 / 9;
  position: relative;
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);

  max-width: 100%;
  width: 100%;
  height: 100vh;
  border-radius: 0px;

  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  opacity: 0;
  bottom: -15px;
  transition: all 0.08s ease; .wrapper
  opacity: 1;
  bottom: 0;
  transition: all 0.13s ease;

  content: "";
  bottom: 0;
  width: 100%;
  z-index: -1;
  position: absolute;
  height: calc(100% + 35px);
  pointer-events: none;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);

  height: 7px;
  width: 100%;
  cursor: pointer;

.video-timeline .progress-area
  height: 3px;
  position: relative;
  background: rgba(255, 255, 255, 0.6);

.progress-area span
  position: absolute;
  left: 50%;
  top: -25px;
  font-size: 13px;
  color: #fff;
  pointer-events: none;
  transform: translateX(-50%);

.progress-area .progress-bar
  width: 0%;
  height: 100%;
  position: relative;
  background: #2289ff;

  content: "";
  right: 0;
  top: 50%;
  height: 13px;
  width: 13px;
  position: absolute;
  border-radius: 50%;
  background: #2289ff;
  transform: translateY(-50%);

.progress-bar::before, .progress-area span
  display: none;

.video-timeline:hover .progress-bar::before,
.video-timeline:hover .progress-area span
  display: block;

.wrapper .video-controls
  padding: 5px 20px 10px;

.video-controls .options
  width: 100%;

.video-controls .options:first-child
  justify-content: flex-start;

.video-controls .options:last-child
  justify-content: flex-end;

.options button
  height: 40px;
  width: 40px;
  font-size: 19px;
  border: none;
  cursor: pointer;
  background: none;
  color: #efefef;
  border-radius: 3px;
  transition: all 0.3s ease;

.options button :where(i, span) 
  height: 100%;
  width: 100%;
  line-height: 40px;

.options button:hover :where(i, span)
  color: #fff;

.options button:active :where(i, span)
  transform: scale(0.9);

.options button span
  font-size: 23px;

.options input
  height: 4px;
  margin-left: 3px;
  max-width: 75px;
  accent-color: #0078FF;

.options .video-timer
  color: #efefef;
  margin-left: 15px;
  font-size: 14px;

.video-timer .separator
  margin: 0 5px;
  font-size: 16px;
  font-family: "Open sans";

  display: flex;
  position: relative;

.playback-content .speed-options
  position: absolute;
  list-style: none;
  left: -40px;
  bottom: 40px;
  width: 95px;
  overflow: hidden;
  opacity: 0;
  border-radius: 4px;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
  transition: opacity 0.13s ease;

  opacity: 1;
  pointer-events: auto;

.speed-options li
  cursor: pointer;
  color: #000;
  font-size: 14px;
  margin: 2px 0;
  padding: 5px 0 5px 15px;
  transition: all 0.1s ease;

.speed-options li:where(:first-child, :last-child)
  margin: 0px;

.speed-options li:hover
  background: #dfdfdf;

  color: #fff;
  background: #3e97fd;

.container video
  width: 100%;

@media screen and (max-width: 540px) 
  .wrapper .video-controls
    padding: 3px 10px 7px;
  .options input, .progress-area span
    display: none!important;
  .options button
    height: 30px;
    width: 30px;
    font-size: 17px;
  .options .video-timer
    margin-left: 5px;
  .video-timer .separator
    font-size: 14px;
    margin: 0 2px;
  .options button :where(i, span) 
    line-height: 30px;
  .options button span
    font-size: 21px;
  .options .video-timer, .progress-area span, .speed-options li
    font-size: 12px;
  .playback-content .speed-options
    width: 75px;
    left: -30px;
    bottom: 30px;
  .speed-options li
    margin: 1px 0;
    padding: 3px 0 3px 10px;
  .right .pic-in-pic
    display: none;

Last, create a JavaScript file with the name script.js and paste the given codes into your JavaScript file. Remember, you’ve to create a file with a .js extension.

const container = document.querySelector(".container"),
mainVideo = container.querySelector("video"),
videoTimeline = container.querySelector(".video-timeline"),
progressBar = container.querySelector(".progress-bar"),
volumeBtn = container.querySelector(".volume i"),
volumeSlider = container.querySelector(".left input");
currentVidTime = container.querySelector(".current-time"),
videoDuration = container.querySelector(".video-duration"),
skipBackward = container.querySelector(".skip-backward i"),
skipForward = container.querySelector(".skip-forward i"),
playPauseBtn = container.querySelector(".play-pause i"),
speedBtn = container.querySelector(".playback-speed span"),
speedOptions = container.querySelector(".speed-options"),
pipBtn = container.querySelector(".pic-in-pic span"),
fullScreenBtn = container.querySelector(".fullscreen i");
let timer;

const hideControls = () => 
    if(mainVideo.paused) return;
    timer = setTimeout(() => 
    , 3000);


container.addEventListener("mousemove", () => 

const formatTime = time => 
    let seconds = Math.floor(time % 60),
    minutes = Math.floor(time / 60) % 60,
    hours = Math.floor(time / 3600);

    seconds = seconds < 10 ? `0$seconds` : seconds;
    minutes = minutes < 10 ? `0$minutes` : minutes;
    hours = hours < 10 ? `0$hours` : hours;

    if(hours == 0) 
        return `$minutes:$seconds`
    return `$hours:$minutes:$seconds`;

videoTimeline.addEventListener("mousemove", e => 
    let timelineWidth = videoTimeline.clientWidth;
    let offsetX = e.offsetX;
    let percent = Math.floor((offsetX / timelineWidth) * mainVideo.duration);
    const progressTime = videoTimeline.querySelector("span");
    offsetX = offsetX < 20 ? 20 : (offsetX > timelineWidth - 20) ? timelineWidth - 20 : offsetX; = `$offsetXpx`;
    progressTime.innerText = formatTime(percent);

videoTimeline.addEventListener("click", e => 
    let timelineWidth = videoTimeline.clientWidth;
    mainVideo.currentTime = (e.offsetX / timelineWidth) * mainVideo.duration;

mainVideo.addEventListener("timeupdate", e => 
    let currentTime, duration =;
    let percent = (currentTime / duration) * 100; = `$percent%`;
    currentVidTime.innerText = formatTime(currentTime);

mainVideo.addEventListener("loadeddata", () => 
    videoDuration.innerText = formatTime(mainVideo.duration);

const draggableProgressBar = e => 
    let timelineWidth = videoTimeline.clientWidth; = `$e.offsetXpx`;
    mainVideo.currentTime = (e.offsetX / timelineWidth) * mainVideo.duration;
    currentVidTime.innerText = formatTime(mainVideo.currentTime);

volumeBtn.addEventListener("click", () => 
        mainVideo.volume = 0.5;
        volumeBtn.classList.replace("fa-volume-xmark", "fa-volume-high");
        mainVideo.volume = 0.0;
        volumeBtn.classList.replace("fa-volume-high", "fa-volume-xmark");
    volumeSlider.value = mainVideo.volume;

volumeSlider.addEventListener("input", e => 
    mainVideo.volume =;
    if( == 0) 
        return volumeBtn.classList.replace("fa-volume-high", "fa-volume-xmark");
    volumeBtn.classList.replace("fa-volume-xmark", "fa-volume-high");

speedOptions.querySelectorAll("li").forEach(option => 
    option.addEventListener("click", () => 
        mainVideo.playbackRate = option.dataset.speed;

document.addEventListener("click", e => !== "material-symbols-rounded") 

fullScreenBtn.addEventListener("click", () => 
        fullScreenBtn.classList.replace("fa-compress", "fa-expand");
        return document.exitFullscreen();
    fullScreenBtn.classList.replace("fa-expand", "fa-compress");

speedBtn.addEventListener("click", () => speedOptions.classList.toggle("show"));
pipBtn.addEventListener("click", () => mainVideo.requestPictureInPicture());
skipBackward.addEventListener("click", () => mainVideo.currentTime -= 5);
skipForward.addEventListener("click", () => mainVideo.currentTime += 5);
mainVideo.addEventListener("play", () => playPauseBtn.classList.replace("fa-play", "fa-pause"));
mainVideo.addEventListener("pause", () => playPauseBtn.classList.replace("fa-pause", "fa-play"));
playPauseBtn.addEventListener("click", () => mainVideo.paused ? : mainVideo.pause());
videoTimeline.addEventListener("mousedown", () => videoTimeline.addEventListener("mousemove", draggableProgressBar));
document.addEventListener("mouseup", () => videoTimeline.removeEventListener("mousemove", draggableProgressBar));

That’s all, now you’ve successfully built a Custom Video Player in HTML CSS & JavaScript. If your code doesn’t work or you’ve faced any problems, please download the source code files from the given download button. It is free and a zip file will be downloaded that contains the project folder with source code files.


Yhaa You have done it but next? if YOU Want to Get your Others

Join Our Telegram Channel

Join Our YouTube Channel

Related Posts

Leave a Reply

Your email address will not be published.