Transitions are vital ingredients that make a website stand out. They make for a great user experience and have been explored a great deal these last few years.
This tutorial will walk you through handling video transitions in our web applications by building a Netflix-style video player using React Player and Framer motion frameworks.
Similar to Netflix on smart TVs, when our video player mounts, our video starts playing automatically after three seconds. The video has an overlay of the video information adnd a button to play the video. On clicking play, the video overlay fades out, and the video continues playing. When the video ends, the overlay reappears.
Check out the Codesandbox to get started quickly.
GitHub URL: https://github.com/Iheanacho-ai/Hackmamba-Video-Player
## Prerequisites
To get the most out of this tutorial, we need the following:
- A basic understanding of CSS and React Hooks.
- [Node](https://nodejs.org/en/) and it’s package manager, npm. Run the command node -v && npm -v to verify we have them, installed, or install them from here..
- Alternatively, we can use another package manager, [Yarn](https://classic.yarnpkg.com/en/docs/install/#windows-stable).
## Setting up our React app
To create our React app, we go to our terminal or command prompt, using the git cd command, we change the path to the directory we want our app to be created in.
```bash
cd <name of the directory>
Then we run
npx create-react-app <name of our app>
Code language: HTML, XML (xml)
Running these commands scaffolds a React app out of the box. To start a development server on port 3000, we run the following command and navigate to localhost:3000 on our browser
npm run start # or yarn start.
Code language: PHP (php)
We’ll install required packages which are React Player and Framer motion.
React Player
React Player is a React library that enables us to play a variety of URLs, including file paths. With React Player, we can easily alter the properties of our video player and call callback functions depending on player events. It offers excellent media experience in web applications.
To install React Player in our app, we run the command.
npm install react-player # or yarn add react-player
Code language: PHP (php)
Framer Motion
Framer Motion is a React animation library that allows us to create animations quickly. It’s easy to use syntax and even easier to understand documentation makes it an excellent fit for this project.
We run this command, to install Framer Motion in our app.
npm install framer-motion
First, we import the React Player into our App.js file.
import React from 'react';
import ReactPlayer from 'react-player';
Code language: JavaScript (javascript)
This ReactPlayer
component comes with wide range of props that we pass values in to personalize our video player.
To start, we will use the url
prop, the controls
prop and finally, the playing
prop.
The url
prop’s value points to the url of the media we are looking to play. The controls
prop, can be set to a boolean ( either true or false ), if set to true, the video player displays the native player controls, and if not it hides the controls. Lastly we have the playing
prop, this prop is set to a boolean value, which if set to true, plays the media and if set to false, pauses the media.
We could also use the width and height prop to set the values for the width and height respectively of our video player. Failing to do so sets our video player to this default dimensions width: 640px; height: 360px;
which we will use in this tutorial.
Seeing as we are trying to build a different webpage from the one we got when we initially created our React app, we replace the boilerplate code in the App.js file with this block of code below.
// App.js
import React from 'react';
import ReactPlayer from 'react-player';
import './App.css';
const App= () => (
<div className="App">
<div className="player-wrapper">
<ReactPlayer
className = 'react-player'
url = 'https://res.cloudinary.com/amarachi-2812/video/upload/v1622736920/production_ID_4456999_gr6iy4.mp4'
controls = {true}
playing = { true }
/>
</div>
</div>
)
};
export default App;
Code language: JavaScript (javascript)
Writing our React Player component, we pass in the path of our video as the value to the url
prop, and set our controls
and playing
props to true
. This plays the video on mount and displays the native player controls.
Now that we have our primary video player set up, we can start working on our overlay.
Creating an overlay for our app requires a slight change in our file structure. To do that, we create a ‘component’ folder in our ‘src’ folder. This component folder will hold our ‘video-overlay’ folder. The ‘video-overlay’ folder will then contain our files’ video-overlay. jsx’ file and ‘video-overlay.css’ ( this is where we will write the styling for our overlay ).
(project's root directory)
├── node_modules
├── public
├── src
| ├── component
| | ├── video-overlay
| | | ├── video-overlay.css
| | | ├── video-overlay.jsx
| ├── _app.js
| └── index.js
├── package-lock.json
├── package.json
├── README.md
└── .gitignore
In the video-overlay.jsx file, we create the overlay we will use in this tutorial. A div
containing the video’s information and a play button is sufficient.
{/* src/component/video-overlay/video-overlay.jsx */}
import React from 'react';
import './video-overlay.css';
const VideoOverlay = () => (
<div className= 'video-overlay-container'>
<div className= 'video-overlay'>
<h2>dépôt: tenant une fleur</h2>
<p>This is video is inspired by Netflix's Ui, and the title is in French, can you tell!. </p>
<button className= 'play-btn'>Play</button>
</div>
</div>
);
export default VideoOverlay;
Code language: JavaScript (javascript)
Now that we have our overlay, we import it into our App.js file.
import React, { useState } from "react";
import { useEffect } from "react";
import ReactPlayer from "react-player";
import VideoOverlay from "../video-overlay/video-overlay";
import "./video-player";
const App = () =>(
<div className="video-player">
<div className="player-wrapper">
<ReactPlayer
className="react-player"
url="https://res.cloudinary.com/amarachi-2812/video/upload/v1622736920/production_ID_4456999_gr6iy4.mp4"
controls= {true}
playing={true}
/>
{/* This is the video overlay component we just created */}
<VideoOverlay/>
</div>
</div>
);
};
Code language: JavaScript (javascript)
Our overlay is incomplete without the styling. Therefore, we define the style properties of our overlay in our video in our ‘video-overlay.css’ file.
The video overlay container houses the overlay with a height of 640px and a width of 360px. These are the measurement of the video player. Next, we set our video overlay’s position to absolute.
Any element ( in this case, <div className = 'video-overlay-container'></div>
) with a position absolute property, is positioned in relative to the element’s parent instead of the entire viewport. The element directly above it as we see below is the ‘player-wrapper’ div.
The top and bottom property tell us the distance from which we want our element to start. In this tutorial, we have our properties top and bottom set to 0, indicating that we wish our overlay to begin at the top of our video player and end at the bottom.
The actual overlay should only be half of the overlay-container, so we set the width property to 50% of the parent element. We give the overlay a background-color property background-color: rgba(0, 0, 0, 0.822)
. This value gives us a light black background.
.video-overlay-container{
box-sizing: border-box;
width: 640px;
height: 360px;
position: absolute;
top: 0;
bottom: 0;
color: #fff;
font-family: 'Nunito Sans', sans-serif;
}
.video-overlay{
width: 50%;
height: 100%;
background-color: rgba(0, 0, 0, 0.822);
margin-top: 0;
text-align: left;
padding: 30px;
box-sizing: border-box;
}
.play-btn{
width: 90%;
height: 30px;
margin: 0 auto;
text-align: left;
}
Code language: CSS (css)
Three seconds after our video player is mounted, we want to play the video automatically. After five seconds, we want to remove the overlay.
To build that function into our video player, we define states using react hooks to control the different properties of the video and the video player.
In our App.js file, we import the useState
and useEffect
hooks from react.
import React, { useState } from "react";
import { useEffect } from "react";
import ReactPlayer from "react-player";
import VideoOverlay from "../video-overlay/video-overlay";
import "./video-player";
Code language: JavaScript (javascript)
In the block of code below, we define the states variables.
const [overlay, showOverlay] = useState(true);
const [playing, setPlaying] = useState(false);
const [controls, setControls] = useState(false);
Code language: JavaScript (javascript)
The overlay
variable is set to an initial value of true
, this variable will be used to selectively render our overlay. The controls
and playing
variables are set to an initial value of false. The controls
variable will be used to set the controls prop on our React Player component, while the playing
variable, the playing prop.
Next, we write out the functions that will affect these state variables.
const onPlayMedia = () => {
setPlaying(true);
}
const onEndMedia = () => {
showOverlay(true)
setControls(false);
}
useEffect(() => {
setTimeout(() => {
setPlaying(true)
}, 3000);
}, [])
useEffect(() => {
setTimeout(() => {
showOverlay(false)
setControls(true)
}, 5000);
}, [])
Code language: JavaScript (javascript)
The onPlayMedia
function sets our playing
variable to true
. In contrast, the onEndMedia
function sets our overlay
variable to true
and our control
variable to false.
Another hook we get from react is the useEffect hook. The useEffect hook takes in as a parameter, a function and an array of dependencies.
Passing an empty array for the hook dependencies causes the functions in the useEffect hook to run only once when the app mounts.
In the code block above both, the useEffect hooks run a setTimeout
function and have empty arrays for dependencies.
The first useEffect hook sets the playing
variable to true after 3000ms ( 3s ). The second useEffect hook, sets our overlay
variable to false and our control
variable to true after 5000ms ( 5s ).
Lastly, we pass in these variables and functions as values to their respective React player props. The playing
variable to the playing prop, and the controls
variable to the controls prop.
<div className="video-player">
<div className="player-wrapper">
<ReactPlayer
className="react-player"
url="https://res.cloudinary.com/amarachi-2812/video/upload/v1622736920/production_ID_4456999_gr6iy4.mp4"
controls={controls}
pip={true}
onPlay={onPlayMedia}
onEnded={onEndMedia}
playing={playing}
/>
<VideoOverlay
onPlayMedia={onPlayMedia}
overlay={overlay}
/>
</div>
</div>
Code language: HTML, XML (xml)
The React Player allows for functions to be passed in as props. We take advantage of that by passing the onPlayMedia
and onEndMedia
function to the props onPlay
and onEnd.
The onPlay
prop calls the function when the media starts playing and onEnd
when the media ends.
Finally, we pass the onPlayMedia
function as props into our ‘VideoOverlay’ component so that the play button on the overlay can play the video.
We also pass the overlay
variable so that our ‘Video-Overlay’ component can be aware of when we want to mount or unmount the overlay in our app.
When we are done, our App
component should look like this.
const App = () => {
const [overlay, showOverlay] = useState(true);
const [playing, setPlaying] = useState(false);
const [controls, setControls] = useState(false);
const onPlayMedia = () => {
setPlaying(true);
}
const onEndMedia = () => {
showOverlay(true)
setControls(false);
}
useEffect(() => {
setTimeout(() => {
setPlaying(true)
}, 3000);
}, [])
useEffect(() => {
setTimeout(() => {
showOverlay(false)
setControls(true)
}, 5000);
}, [])
return (
<div className="video-player">
<div className="player-wrapper">
<ReactPlayer
className="react-player"
url="https://res.cloudinary.com/amarachi-2812/video/upload/v1622736920/production_ID_4456999_gr6iy4.mp4"
controls={controls}
pip={true}
onPlay={onPlayMedia}
onEnded={onEndMedia}
playing={playing}
/>
<VideoOverlay
onPlayMedia={onPlayMedia}
overlay={overlay}
/>
</div>
</div>
);
};
export default App;
Code language: JavaScript (javascript)
To use Framer Motion to animate elements in our app, we start by importing motion
and AnimatePresence
into the video-overlay.jsx file, containing the VideoOverlay
component that we are looking to animate in and animate out.
import { motion, AnimatePresence } from "framer-motion"
Code language: JavaScript (javascript)
Framer Motion lets us define animation values in an object. We can then pass this object in as a prop to the component or element that needs to be animated ( in this case, the ‘VideoOverlay’ component ).
We define our animation object, variants
, in the App.js file.
const variants = {
hidden: {
opacity: 0
},
visible: {
opacity: 1,
transition: {
duration: 0.7
}
}
}
Code language: JavaScript (javascript)
This object has two properties which are also objects, hidden ( what the initial value of the property of the element should be ) and visible ( what we want the element to be animated to ). In this case, we are animating the opacity property from 0 to 1 for a duration of 0.7seconds.
Next, we pass the variants
object into our VideoOverlay component as a prop and assign it a prop name of variants
. This way, our VideoOverlay component can access the object.
<VideoOverlay onPlayMedia = {onPlayMedia} variants = {variants} overlay={overlay}/>
Code language: HTML, XML (xml)
In the next step, we will be using this variant
prop to animate our overlay.
To animate any element in our app, we replace the HTML elements with motion elements. There is a motion element for every HTML and SVG element (e.g. <motion.div>
, <motion.h2>
). These motion elements can accept several props, which allows us to add animations or define animation behaviors.
Framer Motion’s AnimatePresence
detects what elements are about to be unmounted, removed from our webpage and lets us animate them out.
In our ‘video-overlay.jsx’ file, we wrap our VideoOverlay component with the AnimatePresence
component. Then, we check for the overlay property we received as prop from the App component and use it to render our overlay component selectively using the framer motion syntax.
{/* src/component/video-overlay/video-overlay.jsx */}
import React from 'react';
import { motion, AnimatePresence } from "framer-motion"
import './video-overlay.css';
const VideoOverlay = ({onPlayMedia, variants, overlay }) => (
<AnimatePresence>
{
overlay && (
<motion.div className="video-overlay-container"
key = 'overlay'
initial = "hidden"
animate = "visible"
exit = {{opacity: 0}}
variants = {variants}
>
<div className= 'video-overlay'>
<h2>dépôt: tenant une fleur</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Delectus, eos fugiat! Nam veritatis voluptatem fuga omnis dicta est molestias numquam fugiat odio maxime, sed veniam dolores rem iusto laudantium delectus!</p>
<button className= 'play-btn' onClick= {onPlayMedia}>Play</button>
</div>
</motion.div>
)
}
</AnimatePresence>
);
export default VideoOverlay;
Code language: JavaScript (javascript)
We replaced the HTML div with Motion’s div. Like any other Motion element, the <motion.div>
has key-value pairs props that describe the animation’s behaviour.
The initial
prop, describes the initial properties of our element and is therefore set to the hidden value. The animate
prop, describes the new properties we want our element to be animated to. It is set to visible
. These values, hidden and visible, are accessed from the variants
object.
The variants
object is then passed as the value of the variants
prop.
We use the exit
prop to specify how the element should be animated out, which is opacity 0.
With these, we completed the development of the Netflix-styled animation on video overlays. Here’s what it looks like:
In this article, we created a video player with React Player. Then, we handled video playback transitions with the React animation library Framer Motion. With Framer Motion, we animated in and out our overlay after a given period depending on different player events.
You may also find the following resources necessary.