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