How I build a YouTube Video Player with ReactJS: Building the Play Button
Tags: javascript, webdev, react, programming
Published: 2023-12-15 11:02:31

In the previous blog post, we dug deep into the architecture of the Project, if you haven't read it please do read it [here](https://dev.to/keyurparalkar/building-with-react-js-create-your-own-youtube-video-player-starting-with-basics-1lpp). This post is going to be a very short one. In this post, we will be building our first control toolbar component which is the Play/Pause button. Before we jump into building the play and pause control button, let us first start with building the ControlToolbar Container component.

So without any further ado let us get started.

## Building the ControlToolbar Component

![ControlToolbar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xj4nmxft96x3gyjgmymg.png)

Do you see the portion highlighted at the top(the pink one)? That’s `ControlToolbar` component and that’s what we are going to be building in this section.Before we start building, let us set some basic expectations from this component:

- While the video is playing, the toolbar should be visible when the mouse is hovering over the video. This bar would be hidden if we were not hovering over the video.
- If the video is paused, this toolbar would be visible all the time irrespective of mouse being hovered over video or not.
 
![Toolbar visibility in different states](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zaryuoazrswpc2xo4cje.gif)    

> _💡 **NOTE:** If you have doubts check out YouTube and you will understand what I am trying to say. Ok now let us start building this component._

From our previous blog post, we know that this project comprises 3 components that come under one parent component which we call `YoutubePlayer` component. We use this same parent component to drive the hovering expectations(discussed above) with the help of CSS.

Inside `YoutubePlayer.tsx` component, add the following CSS inside the `StyledVideoContainer` component such that the whole CSS looks like below

```jsx
const StyledVideoContainer = styled.div`
    position: relative;
    width: fit-content;

    .video-controls {
        opacity: 0;
    }

    &:hover .video-controls {
        opacity: 1;
    }
`;
```

So here is what’s happening:

- `.video-controls` class is the class-name assigned to our `ControlToolbar` component which we will look into it later in this post.
- At start, while the video is playing we keep the opacity of the toolbar to 0. In this way, the toolbar will be hidden.
- When we hover over the entire video which is `YoutubePlayer` component we want to show the toolbar, so we set its opacity to 1.

There is one caveat though, we didn't implement the behavior of toolbar where it should be always visible when the video is paused. Hold on to this thought, we will come to this when we have the `ControlToolbar` component ready.

## Building the `ControlToolbar` component

`ControlToolbar` component is a container component that will comprise multiple controls such as:

- Play/Pause Button
- Mute/Unmute Button
- Volume Slider etc.

To proceed with the implementation of the Play/Pause button, we must build this toolbar component. So without further ado let us get started. Create a `ControlToolbar.tsx` file inside the `components` folder and place the following content in it:

```tsx
import { motion } from "framer-motion";
import { useContext } from "react";
import styled from "styled-components";
import { PlayerContext } from "../context";
import PlayButton from "./PlayButton";
import VolumeControl from "./VolumeControl";

const ControlToolbar = () => {
  return (
    <div className="video-controls">
      <PlayButton />
    </div>
  );
};

export default ControlToolbar;
```

Next, we convert the `div` with class `video-controls` to a styled component. Create a styled component named `StyledVideoControl` and place the following CSS in it:

```jsx
const StyledVideoControl = styled(motion.div)<{ isPlaying?: boolean }>`
    position: absolute;
    width: 100%;
    color: #eee;
    bottom: 0rem;
    background: #ffffff00;
    background: linear-gradient(180deg, #ffffff00, #010101);
    ${(props) => (!props.isPlaying ? 'opacity: 1 !important' : '')};
`;
```

This styled component does two things:

- Its position is absolute so that it always stays on top of the `video`.
- The other is the `opacity` property. We set it to `1` because whenever the video is paused we want the toolbar to be displayed all the time irrespective of hover. This was the case we talked about in the previous section.

Now, we use this styled component by replacing the existing `div.video-controls` with `StyledVideoControls`:

```tsx
import { motion } from "framer-motion";
import { useContext } from "react";
import styled from "styled-components";
import { PlayerContext } from "../context";
import PlayButton from "./PlayButton";
import VolumeControl from "./VolumeControl";

const StyledVideoControl = styled(motion.div)<{ isPlaying?: boolean }>`
    position: absolute;
    width: 100%;
    color: #eee;
    bottom: 0rem;
    background: #ffffff00;
    background: linear-gradient(180deg, #ffffff00, #010101);
    ${(props) => (!props.isPlaying ? 'opacity: 1 !important' : '')};
`;

const ControlToolbar = () => {
	const { isPlaying } = useContext(PlayerContext);

  return (
    <StyledVideoControl className="video-controls" isPlaying={isPlaying}>
      <PlayButton />
    </StyledVideoControl>
  );
};

export default ControlToolbar;
```

Also make sure that you call our `ControlToolbar` component inside its parent i.e. `YoutubePlayer` like below

```tsx
import styled from "styled-components";
import { PlayerProvider } from "../context";

const StyledVideoContainer = styled.div`
  position: relative;
  width: fit-content;
`;

const YoutubePlayer = () => {
  return (
    <PlayerProvider>
      <StyledVideoContainer>
		      <Video />
					<BezelIcon />
					<ControlToolbar />
      </StyledVideoContainer>
    </PlayerProvider>
  );
};

export default YoutubePlayer;
```

Pretty cool right!. Awesome now we have our basic structure ready for the toolbar, now it is time to develop our first control which is the Play and Pause button

## Building Play/Pause Control

Create a file named: `PlayButton.tsx` inside the `components` folder and place the following content in it:

```tsx
import { useContext } from "react";
import { HiMiniPlay, HiMiniPause } from "react-icons/hi2";
import { PlayerContext, PlayerDispatchContext } from "../context";
import { PLAY_PAUSE } from "../context/actions";

export const StyledIconButton = styled.button<IconButtonProps>`
  background-color: transparent;
  border: none;
  width: 45px;
  float: left;
  margin-bottom: 3px;
  color: inherit;
  font-size: ${(props) =>
    props.iconSize || props.iconSize !== "" ? props.iconSize : ""};
`;

const PlayButton = () => {
  const { isPlaying } = useContext(PlayerContext);
  const dispatch = useContext(PlayerDispatchContext);
  const onPlayPause = () => {
    dispatch({ type: PLAY_PAUSE, payload: !isPlaying });
  };

  return (
    <StyledIconButton onClick={onPlayPause}>
      {isPlaying ? <HiMiniPause size="25px" /> : <HiMiniPlay size="25px" />}
    </StyledIconButton>
  );
};

export default PlayButton;
```

This component is pretty similar to `BezelIcon` component. It makes use of both the state and action context i.e. `PlayerContext` and `PlayerDispatchContext` and dispatches the action `PLAY_PAUSE` whenever button container: `StyledIconButton` is clicked. Based on the value of `isPlaying` we show the play and pause button.

> 💡 _**Tip:** Since Icons are something that we are going to use a lot, therefore, we move the `StyledIconButton` to the utils where it is accessible to more components._


Create a folder outside of `components` named: `utils` and create a new file: `index.tsx`:

```tsx
import styled from "styled-components";

type IconButtonProps = {
  iconSize?: string;
};

export const StyledIconButton = styled.button<IconButtonProps>`
  background-color: transparent;
  border: none;
  width: 45px;
  float: left;
  margin-bottom: 3px;
  color: inherit;
  font-size: ${(props) =>
    props.iconSize || props.iconSize !== "" ? props.iconSize : ""};
`;
```

We make use of [react-icons](https://react-icons.github.io/react-icons/) to display the play and pause indications.

```tsx
import { useContext } from "react";
import { HiMiniPlay, HiMiniPause } from "react-icons/hi2";
import { PlayerContext, PlayerDispatchContext } from "../context";
import { PLAY_PAUSE } from "../context/actions";
import { StyledIconButton } from "../utils";

const PlayButton = () => {
  const { isPlaying } = useContext(PlayerContext);
  const dispatch = useContext(PlayerDispatchContext);
  const onPlayPause = () => {
    dispatch({ type: PLAY_PAUSE, payload: !isPlaying });
  };

  return (
    <StyledIconButton onClick={onPlayPause}>
      {isPlaying ? <HiMiniPause size="25px" /> : <HiMiniPlay size="25px" />}
    </StyledIconButton>
  );
};

export default PlayButton;
```

So here we are all set up, with our first control the play pause button is finally done. Here is how it will look

![Our outcome](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d5b1nrscn9at4so9odel.gif)

## Summary

To summarize, we learned,

- What a `ControlToolbar` component is, we also learned how to implement it.
- We looked into the implementation of `Play/Pause` control.

In the next blog post of this series we are going to talk about building one of the crucial controls which is `VolumeControl` so stay tuned for more!!

The entire code for this tutorial can be found [here](https://github.com/keyurparalkar/react-youtube-player-clone).

Thank you for reading!

Follow me on [twitter](https://twitter.com/keurplkar), [github](http://github.com/keyurparalkar), and [linkedIn](https://www.linkedin.com/in/keyur-paralkar-494415107/).