Skip Navigation

Scott Spence

Create a Video Overlay with Hooks

2 min read
Hey! Thanks for stopping by! Just a word of warning, this post is 5 years old, wow! If there's technical information in here it's more than likely out of date.

Create a Video overlay with React hooks.

I had to create a video overlay for a project I was working on. This example use a portal to render the player with react-player.

// useModal.js
import { useState } from 'react'

export const useModal = () => {
  const [isShowing, setIsShowing] = useState(false)

  const toggle = () => {
    setIsShowing(!isShowing)
  }

  return {
    isShowing,
    toggle,
  }
}
// VideoPlayer.js
import React from 'react'
import ReactPlayer from 'react-player'

export const VideoPlayer = props => {
  return (
    <ReactPlayer
      {...props}
      url="https://www.youtube.com/watch?reload=9&v=YE7VzlLtp-4"
      playing={props.playing}
      controls
      width="100%"
      height="100%"
      css={{
        position: `absolute`,
        top: 0,
        left: 0,
      }}
    />
  )
}
// VideoModal.js
import React from 'react'
import ReactDOM from 'react-dom'
import styled from 'styled-components'
import closePrimary from '../../static/buttonClose.svg'
import { VideoPlayer } from './VideoPlayer'

const ModalOverlay = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: darkgrey;
  opacity: 0.5;
`

const ModalWrapper = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  outline: 0;
  position: fixed;
  top: 10vh;
  bottom: 10vh;
  left: 10vh;
  right: 10vh;
  display: flex;
`

const ModalHeader = styled.div`
  position: fixed;
  top: 20px;
  right: 20px;
  padding: 1.5rem;
  z-index: 1;
`

const Modal = styled.div`
  background: ${({ theme }) => theme.primary};
  position: relative;
  border-radius: 3px;
  display: flex;
  flex-direction: column;
  flex: 1;
`

const CloseButton = styled.div`
  padding: 30px;
  border-radius: 50%;
  margin: -1rem -1rem -1rem auto;
  cursor: pointer;
  background-repeat: no-repeat;
  background-image: url(${closePrimary});
`

const PlayerWrapper = styled.div`
  position: relative;
  flex: 1;
  padding: 50px 0;
`

const PlayerSizer = styled.div`
  width: 0;
  height: 100%;
  padding-right: 82%;
  margin: 0 auto;
`

export const VideoModal = ({ isShowing, hide }) =>
  isShowing
    ? ReactDOM.createPortal(
        <>
          <ModalOverlay onClick={hide} />
          <ModalWrapper
            aria-modal
            aria-hidden
            tabIndex={-1}
            role="dialog"
          >
            <Modal>
              <ModalHeader>
                <CloseButton
                  data-dismiss="modal"
                  aria-label="Close"
                  onClick={hide}
                />
              </ModalHeader>
              <PlayerWrapper>
                <PlayerSizer>
                  <VideoPlayer playing={true} />
                </PlayerSizer>
              </PlayerWrapper>
            </Modal>
          </ModalWrapper>
        </>,
        document.body
      )
    : null

Then in the component:

import React from 'react'
import { VideoModal } from '../components/VideoModal'
import { useModal } from '../hooks/useModal'
import styled from 'styled-components'
import playSvg from '../../static/playIcon.svg'

const Wrapper = styled.div`
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
`

const PlayDiv = styled.div`
  /* margin: 0 auto; */
  background-repeat: no-repeat;
  height: 50px;
  width: 50px;
  background-image: url(${playSvg});
`

export default () => {
  const { isShowing, toggle } = useModal()
  return (
    <>
      <Wrapper>
        <VideoModal isShowing={isShowing} hide={toggle} />
        {/* <button onClick={toggle}>Click This Button</button> */}
        <PlayDiv onClick={toggle} />
      </Wrapper>
    </>
  )
}

There's a reactions leaderboard you can check out too.

Sign up for the newsletter

Want to keep up to date with what I'm working on?

Join other developers and sign up for the newsletter.

I care about the protection of your data. Read the Privacy Policy for more info.

Copyright © 2017 - 2026 - All rights reserved Scott Spence