DEV Community

Cover image for Create a custom video player in React 📽️
Avneesh Agarwal
Avneesh Agarwal

Posted on • Updated on

Create a custom video player in React 📽️

Wassup guys, in this tutorial we are going to see how to build a custom video player in React. Let's jump straight into it!

jump right in

Setup

Create a new react app



npx create-react-app custom-video-player


Enter fullscreen mode Exit fullscreen mode

Cleanup

  • Delete everything in the app div in App.js.


import "./App.css";

function App() {
  return <div className="app"></div>;
}

export default App;


Enter fullscreen mode Exit fullscreen mode
  • Delete everything in App.css

  • in index.css add-



* {
  margin: 0;
}


Enter fullscreen mode Exit fullscreen mode

Create the UI for our Video player

Adding the Video

Inside the app div add a video tag with the src of your video, I am also going to add a className for styling-



 <video
    className="video"
    src="https://res.cloudinary.com/dssvrf9oz/video/upload/v1635662987/pexels-pavel-danilyuk-5359634_1_gmixla.mp4"
 ></video>


Enter fullscreen mode Exit fullscreen mode

Adding the controls of the videos

Below the video component, I will add this div which has some Svgs as icons. You can use direct Svgs like me or use an icon library for the icons :).



  <div className="controlsContainer">
        <div className="controls">
          <img className="controlsIcon" alt="" src="/backward-5.svg" />
          <img className="controlsIcon--small" alt="" src="/play.svg" />
          <img className="controlsIcon" alt="" src="/forward-5.svg" />
        </div>
  </div>


Enter fullscreen mode Exit fullscreen mode

Adding the progress bar for time

We are also going to create a progress bar that shows the current time and total time of the video.



 <div className="timecontrols">
        <p className="controlsTime">1:02</p>
        <div className="time_progressbarContainer">
          <div style={{ width: "40%" }} className="time_progressBar"></div>
        </div>
        <p className="controlsTime">2:05</p>
   </div>


Enter fullscreen mode Exit fullscreen mode

Forgive me for not having very good naming conventions in classes. I have forgotten how to name my classes because of Tailwind :P

Styling the UI

The video player looks very ugly right now, so let's style it. In App.css I am going to add some stylings-



/* Main Container */

.app {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

/* Video */

.video {
  width: 100vw;
  height: 100vh;
}

/* Controls */

.controlsContainer {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100vw;
  background-color: transparent;
  margin-top: -50vw;
  padding: 0 40px;
  z-index: 20;
}

.controls {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  padding-top: 18rem;
  margin: auto;
}

.controlsIcon {
  width: 40px;
  height: 40px;
  cursor: pointer;
  margin-left: 10rem;
  margin-right: 10rem;
}

.controlsIcon--small {
  width: 32px;
  height: 32px;
  cursor: pointer;
  margin-left: 10rem;
  margin-right: 10rem;
}

/* The time controls section */

.timecontrols {
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  position: absolute;
  bottom: 4rem;
  margin-left: 10vw;
}

.time_progressbarContainer {
  background-color: gray;
  border-radius: 15px;
  width: 75vw;
  height: 5px;
  z-index: 30;
  position: relative;
  margin: 0 20px;
}

.time_progressBar {
  border-radius: 15px;
  background-color: indigo;
  height: 100%;
}

.controlsTime {
  color: white;
}


Enter fullscreen mode Exit fullscreen mode

Now our video player would look like this-

image.png

Adding the logic to the player

To work on the functionalities we first need to attach a ref to the video with the useRef hook. So follow the steps given below:

  • Create a ref like this-


const videoRef = useRef(null);


Enter fullscreen mode Exit fullscreen mode
  • Import the useRef hook from react


import { useRef } from "react";


Enter fullscreen mode Exit fullscreen mode
  • Attach it to the video


 <video
    ref={videoRef}
    className="video"
    src="https://res.cloudinary.com/dssvrf9oz/video/upload/v1635662987/pexels-pavel-danilyuk-5359634_1_gmixla.mp4"
 ></video>


Enter fullscreen mode Exit fullscreen mode

Play and Pause functionality

For play and pause create a simple function, which takes an argument of control and based on the control it will play or pause the video-



 const videoHandler = (control) => {
    if (control === "play") {
      videoRef.current.play();
    } else if (control === "pause") {
      videoRef.current.pause();
    }
  };


Enter fullscreen mode Exit fullscreen mode

Now in the play.svg image, we will add an onClick function to start the video.



  <img
     onClick={() => videoHandler("play")}
     className="controlsIcon--small"
     alt=""
     src="/play.svg"
     />


Enter fullscreen mode Exit fullscreen mode

If you click on the icon the video will play!

Changing the icon based on the playing/paused state
To achieve this I am going to use the useState hook. Create a playing state like this-



const [playing, setPlaying] = useState(false);


Enter fullscreen mode Exit fullscreen mode

In the const video handler function, we need to change the value onClick of them like this-



const videoHandler = (control) => {
    if (control === "play") {
      videoRef.current.play();
      setPlaying(true);
    } else if (control === "pause") {
      videoRef.current.pause();
      setPlaying(false);
    }
  };


Enter fullscreen mode Exit fullscreen mode

Changing the icon
Where we have the play icon, now we will render it based on a condition with the help of a ternary operator -



  {playing ? (
            <img
              onClick={() => videoHandler("pause")}
              className="controlsIcon--small"
              alt=""
              src="/pause.svg"
            />
          ) : (
            <img
              onClick={() => videoHandler("play")}
              className="controlsIcon--small"
              alt=""
              src="/play.svg"
            />
          )}


Enter fullscreen mode Exit fullscreen mode

Now, we can play and pause the video 🥳

Forwarding and reverting the video

I am going to create very simple functions for this-



 const fastForward = () => {
    videoRef.current.currentTime += 5;
  };

  const revert = () => {
    videoRef.current.currentTime -= 5;
  };


Enter fullscreen mode Exit fullscreen mode

Now we will add these functions as onClick of the respective buttons.

Forward



<img
  onClick={fastForward}
  className="controlsIcon"
  alt=""
  src="/forward-5.svg"
     />


Enter fullscreen mode Exit fullscreen mode

Revert



<img
  onClick={revert}
  className="controlsIcon"
  alt=""
  src="/backward-5.svg"
     />


Enter fullscreen mode Exit fullscreen mode

Time progress bar

Get the length of the video

To get the length of the video, follow the following steps

  • Give an id to the video component


 <video
    id="video1"
    ref={videoRef}
    className="video"
    src="https://res.cloudinary.com/dssvrf9oz/video/upload/v1635662987/pexels-pavel-danilyuk-5359634_1_gmixla.mp4"
 ></video>


Enter fullscreen mode Exit fullscreen mode
  • Create a state to store the video length


const [videoTime, setVideoTime] = useState(0);


Enter fullscreen mode Exit fullscreen mode
  • Set the video time like this on the play of the video


if (control === "play") {
      videoRef.current.play();
      setPlaying(true);
      var vid = document.getElementById("video1");
      setVideoTime(vid.duration);
    }


Enter fullscreen mode Exit fullscreen mode

Now we can use the videoTime variable instead of hardcoded time. This string manipulation will make the time in a format like- 1:05



  <p className="controlsTime">
    {Math.floor(videoTime / 60) + ":" + ("0" + Math.floor(videoTime % 60)).slice(-2)}
 </p>


Enter fullscreen mode Exit fullscreen mode

Getting the current time of the video

To get the current time of video we will need to use a function that runs every second, so I am going to use window.setInterval for the same.



window.setInterval(function () {
    setCurrentTime(videoRef.current?.currentTime);
  }, 1000);


Enter fullscreen mode Exit fullscreen mode

Now as always, we need to create a state to store the value-



const [currentTime, setCurrentTime] = useState(0);


Enter fullscreen mode Exit fullscreen mode

Instead of the hard code value, we will use the variable



<p className="controlsTime">
    {Math.floor(currentTime / 60) + ":" + ("0" + Math.floor(currentTime % 60)).slice(-2)}
</p>


Enter fullscreen mode Exit fullscreen mode

Getting the progress and setting it to the progress bar

Create another state for progress-



const [progress, setProgress] = useState(0);


Enter fullscreen mode Exit fullscreen mode

Now inside the window.setInterval function that we created, add another line-



setProgress((videoRef.current?.currentTime / videoTime) * 100);


Enter fullscreen mode Exit fullscreen mode

The function would look like this now-



window.setInterval(function () {
    setCurrentTime(videoRef.current?.currentTime);
    setProgress((videoRef.current?.currentTime / videoTime) * 100);
  }, 1000);


Enter fullscreen mode Exit fullscreen mode

Our custom video player is now ready 🎉🎊

Useful links-

GitHub repository

ReactJS docs

All socials

Top comments (3)

Collapse
 
baileys profile image
Arthur Li

Try a onTimeUpdate event. I think it's better than creating Intervals update

Collapse
 
avneesh0612 profile image
Avneesh Agarwal

Oh cool. I will try it

Collapse
 
consultantvengage profile image
Rahul Pandey

Does not work. Do you have a demo version running somewhere