Adding Netflix-style video overlays Transitions with NuxtJS

Banner for a MediaJam post

Amarachi Iheanacho

Transitions have solidified themselves as an important part of web applications, as they have been used in different ways to capture users' attention. They, however, have also been known to be a little tricky to implement. This problem has been mitigated by the release of UI libraries over the years.

This article will walk us through embedding a video player and handling video overlay transitions similar to what we see on Netflix, using Nuxt.js.

What we will be building

Akin to smart TV's Netflix, we want our video to start playing automatically after three seconds when our video player mounts. After five seconds, we want our overlay to fade out, only to fade back in when the video ends.

Check out the Codesandbox to get started quickly.

GitHub URL:


To get the most out of this article it is important that we have the following:

  • A basic understanding of CSS, JavaScript and Vue.js
  • Node and it’s package manager, npm. Run the command node -v && npm -v to verify we have them installed, or install them from here. It is recommended that we have the latest version.
  • Alternatively, we can use another package manager, Yarn.
  • Understanding Nuxt.js would help us follow through with this tutorial quicker, but it is not entirely required.
  • A Cloudinary account, if you don’t have one, you can create one here.

Setting up our Nuxtjs app

Nuxt.js is an open-source vue.js frontend development framework that allows us to create universal web applications without stress, render statically Vue.js applications without having a server, and enables functionalities like server-side rendering, static site generating, etc. in our project.

To create a nuxt.js app, we go to our terminal and run the command below.

NOTE: If you are on windows and using Git Bash you might have issues with the arrows, so it is advisable that you use the Powershell terminal instead

1npm init nuxt-app <project-name>
3 #or
5 npx create-nuxt-app <project-name>
7 #or
9 yarn create nuxt-app <project-name>

Running this command will trigger a set of question prompts. In the picture below, this is the setup I used.

Nuxtjs setup prompts

After that, we run these commands

1cd <project name>
3 npm run dev
5 #or
7 yarn dev

This would change the directory to our project and run it on the browser, to see our app go to http://localhost:3000/

Nuxtjs Setup index page

Installing dependencies

In this section of the tutorial, we will install the dependencies required for this project. These dependencies are Cloudinary for the video player and Vue2-animate for handling the transitions.


Cloudinary is a cloud-based service that provides an end-to-end image and video management solution, including uploads, storage, manipulations, optimizations, and delivery.

It also allows developers to embed video players in their app that handles video events effectively.

To enable our nuxt app to use these Cloudinary features, we will add the video player assets in the head section of our nuxt.config.js file.

1// nuxt.config.js
3 export default {
4 head: {
5 ...
6 link: [
7 ...
8 { rel: 'stylesheet', href: '' }
9 ],
10 script: [
11 { src: '' },
12 { src: '' },
13 ],
14 },
16 };

Next up, we create a .env at the root of our project.

1touch .env

After creating our .env file, we go to our Dashboard, in the Account Details section we can see our cloud name, we copy paste it in our .env file.

1CLOUD_NAME = <Cloudinary-cloud-name>


Vue2-animate is a great UI library created for the Vue.js framework. It helps developers create high-performance and stunning animations with just a few lines of code.

To install vue2-animate in our project, we run this command.

1npm install --save vue2-animate
3 #or
5 yarn add vue2-animate

Creating our Video Player

In our index.vue file, we embed the Cloudinary video player in our project using the HTML5 native video element.

We then give the element an id of video-player and a class of cld-video-player .

2 <div>
3 <video
4 id= "video-player"
5 class="cld-video-player"
6 >
7 </video>
8 </div>
9 </template>

In our mounted lifecycle hook, we create a Cloudinary instance. Doing this in our mounted lifecycle hook allows the instance to be created once the app mounts.

1// pages/index.vue
3 <script>
5 export default {
6 data(){
7 return{
8 cld: null,
9 player: null,
10 video: "production_ID_4456999_gr6iy4"
11 }
12 },
13 mounted(){
14 this.cld={
15 cloud_name: process.env.CLOUD_NAME,
16 secure: true
17 })
18 this.player = this.cld.videoPlayer(
19 'video-player'
20 );
21 this.player.source(;
22 }
24 }
27 </script>

In the data object, we define three variables:

  • The cld variable holds the Cloudinary instance we will create.
  • The player variable holds the new Cloudinary video player we will instantiate on mount. We do this by passing the id video-player (id of our video element) to the VideoPlayer method.
  • The video variable holds the id of the video we are looking to play stored on cloudinary.

In our mounted lifecycle hook, we create a Cloudinary instance from the Cloudinary object by providing the cloud name we stored in our .env file and secure: true, as arguments.

We then instantiate the Cloudinary video player using the videoPlayer method and passing either the video player id or the video player itself, as as argument.

After we create our player, we sourced the video we are looking to play.

Next, in the style section of our index.vue file, we add a bit of styling to our video player, with a width of 500px and a height of 300px.

1<style scoped>
2 div{
3 margin: 0;
4 padding: 0;
5 }
6 .cld-video-player{
7 width: 500px;
8 height: 300px;
9 }
10 </style>

With that we have embedded a Cloudinary video player in our project.

Cloudinary Video Player

Creating our overlay

In the template section of our index.vue file, we create our video overlay with the HTML native div element.

1<div class = 'overlay' >
2 <h2 class= 'overlay-header'>bonne vitesse</h2>
3 <p>
4 You look down on where you came from sometimes
5 But you'll have this place to call home, always.
6 </p>
7 <button>Play</button>
8 </div>

Our overlay is incomplete without the styling

2 box-sizing: border-box;
3 font-family: 'Nunito', sans-serif;
4 width: 250px;
5 height: 300px;
6 padding: 10px;
7 background-color: rgba(0, 0, 0, 0.35);
8 color: #fff;
9 position: absolute;
10 top: 7px;
11 left: 7px;
12 bottom: 7px;
13 }
14 .overlay-header{
15 text-align: center;
16 }
17 button{
18 width: 90%;
19 height: 30px;
20 margin: 0 auto;
21 }

We give our overlay a width of 250px (half of our video player) and a height of 300px. Our overlay has an absolute position to sit on our video player.

Selectively rendering the overlay and playing the video.

To selectively render our overlay, we must first create an overlay variable in the data object. This will be used to control our overlay.

1export default {
2 data(){
3 return{
4 cld: null,
5 player: null,
6 video: "production_ID_4456999_gr6iy4",
8 // overlay variable
9 overlay: true,
10 }
11 },
12 mounted(){
13 this.cld={
14 cloud_name: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
15 secure: true
16 })
17 this.player = this.cld.videoPlayer(
18 'video-player'
19 );
20 this.player.source(;
21 }

Next, we add a setTimeout function to remove the overlay after five seconds in our mounted lifecycle hook. Then we use Cloudinary's ended video player event to set the overlay to true when the video ends.

1this.player.on('ended', ()=> {
2 this.overlay = true
3 })
5 setTimeout(() => {
6 this.overlay = false
7 }, 5000)
8 }

We then selectively render the overlay depending on the value of the overlay.

2 <div>
3 <video
4 id= "video-player"
5 class="cld-video-player"
6 >
7 </video>
9 <div class = 'overlay' v-if = 'overlay'>
10 <h2 class= 'overlay-header'>bonne vitesse</h2>
11 <p>
12 You look down on where you came from sometimes
13 But you'll have this place to call home, always.
14 </p>
15 <button> Play</button>
16 </div>
18 </div>
19 </template>

Selectively playing our video.

We want our video to play automatically after three seconds, but we also want the play button on the overlay to play the video.

To achieve this, we use a setTimeout function to play the video after three seconds on the mounted lifecycle hook. We add a function on the method object called playMedia, which also plays the media.

3 export default {
4 data(){
5 return{
6 cld: null,
7 player: null,
8 video: "production_ID_4456999_gr6iy4",
9 overlay: true,
10 }
11 },
12 methods: {
13 playMedia(){
15 }
16 },
18 mounted(){
19 this.cld={
20 cloud_name: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
21 secure: true
22 })
23 this.player = this.cld.videoPlayer(
24 'video-player'
25 );
27 this.player.source(;
29 this.player.on('ended', ()=> {
30 this.overlay = true
31 })
33 // plays the media
35 setTimeout(() => {
37 }, 3000)
39 setTimeout(() => {
40 this.overlay = false
41 }, 5000)
42 }
44 }
47 </script>

Next, we then pass the playMedia method into an onClick event listener on our button.

1<button @click= "playMedia()">Play</button>

Animating our Overlay

To use the vue2-animate library in our project we have to require it, we do this in the script section of our index.vue file.


The vue2-animate allows us to use the transition component to animate our element. This transition component has a name prop that takes in the kind of animation we want our element to have, in this case, fade.

We then specify the duration for the animation using the style prop.

1<transition name="fade">
2 <div class = 'overlay' v-if = 'overlay' style="animation-duration: 1s">
3 <h2 class= 'overlay-header'>bonne vitesse</h2>
4 <p>
5 You look down on where you came from sometimes
6 But you'll have this place to call home, always.
7 </p>
8 <button @click= "playMedia()">Play</button>
9 </div>
10 </transition>

With these we have completed the Netflix-styled Video Overlay animation. Here is what it should look like:

Cloudinary Video Player with Video-Overlay Transitions


In this article we discussed what Cloudinary is, why we would use it, and how to embed its video player in our project. We also discussed the vue2-animate library and used it to animate in and out, our overlay depending on what player event was triggered.


You may find the following resources useful

Amarachi Iheanacho

Frontend Engineer and Technical Writer