Skip to content

Video events trigger on a Next.js Page

Interactivity is at the backbone of modern web pages. This includes collecting information on user interaction, handling form submissions, and managing interactivity on media assets.

This post discusses how to handle user interface interactions with events from a Video on a Next.js web page.

Next.js is a modern React.js framework for building high-performance web applications.

We completed this project in CodeSandbox. You can fork the CodeSandbox project or run the code to get started quickly.

For this post, knowledge of JavaScript and React.js is required. The knowledge of Next.js isn’t mandatory, but preferred.

To create a new project, we use the create next-app command to scaffold a new project. Using yarn, we run:

    yarn create next-app

A prompt appears to enter the project name, which we do to complete the project creation.

Alternatively, we could use NPX with the command:

    npx create-next-app

The boilerplate project scaffolds a landing page with styling using CSS modules.

For this project, we’ll use the Cloudinary-React package to render a video player whose video source is a video stored on Cloudinary. The video is delivered via an optimized content delivery network (CDN), and can be modified using Cloudinary’s robust transformation features.

We install the cloudinary-react package using yarn:

    yarn add cloudinary-react

The cloudinary-react package exports two named components, Video and CloudinaryContext, which we’ll use to render the video player.

On the home page whose component is defined in pages/index.js, we import and render the video player with:

    import { Video, CloudinaryContext, Transformation } from "cloudinary-react";
    export default function IndexPage() {
      return (
        <div>
          Hello World.{" "}
          <CloudinaryContext cloudName="chuloo">
            <Video publicId="video-blog/cat" controls muted width="500px"/>
          </CloudinaryContext>
        </div>
      );
    }
Code language: JavaScript (javascript)

CloudinaryContext receives props of any data we would like to make available to the Cloudinary child components. In this case, we passed our Cloudinary cloud name. You can obtain yours by creating an account on Cloudinary.

We use the Video component to render the video player with a width of 500px. We also specified the video’s public ID, which is stored on Cloudinary. Lastly, we included props that give the video player controls and make it muted on render.

The video player currently looks like this:

The cloudinary-react video player is a wrapper on the traditional HTML5 video element with enhanced properties. It provides an innerRef prop that grants us access to the underlying video element’s methods and properties.

With this, we will use React’s useRef() hook to reference the video element.

With the Video component’s ref, we’ll be able to utilize the onpause and onended events along with all other video events and properties. We create a ref and assign it to the innerRef prop of the Video with:

    import { Video, CloudinaryContext, Transformation } from "cloudinary-react";
    import { useRef } from "react";
    export default function IndexPage() {
      const videoRef = useRef();
      return (
        <div>
          Hello World.{" "}
          <CloudinaryContext cloudName="chuloo">
            <Video publicId="video-blog/cat" controls muted width="500px" 
                   innerRef={videoRef}/>
          </CloudinaryContext>
        </div>
      );
    }
Code language: JavaScript (javascript)

With the ref in place, we will handle actions when video events are triggered. We assign two functions, which we call when the video is paused, and the video ends. We do this in a useEffect hook with:

    import { useRef, useEffect, useState } from "react";
    export default function IndexPage() {
      const [videoEnded, setVideoEnded] = useState(undefined)
        const videoRef = useRef()
        useEffect(() => {
            const video = videoRef.current;
            video.onpause = () => {
                // logic goes in here
            }
            video.onended = () => {
                setVideoEnded(true)
                // logic goes in here
            }
        }, [])
      return (
        // render component here
      );
    }
Code language: JavaScript (javascript)

In the imported useEffect hook, we created a function that triggers when the video is paused or ended.

When the video ends, we store a true boolean value in the component’s state. With this state value, we can handle multiple UI updates. These interactions include:

  • Toasts to display status updates
  • Modals to communicate important information
  • Ads
  • Call to action buttons when a video ends
  • Handle navigation on specific video events
  • Fetch or post data

The interactivity opportunities are boundless.

We will be rendering a timed toast component that fires when the video is paused or ends for this project. We use react-hot-toast for this.

React-hot-toast is a lightweight toast package that is seamless to use. We install it using yarn with the command:

    yarn add react-hot-toast

In the .onpause and .onended functions, we trigger success toasts using the toast functions with:

    import { toast, Toaster } from "react-hot-toast";
    export default function IndexPage() {
      // component logic goes in here
      
      useEffect(() => {
        const video = videoRef.current;
        video.onpause = () => {
          toast.success("The video is paused");
        };
        video.onended = () => {
          setVideoEnded(true);
          toast.success("The video is ended");
        };
      }, []);
      
      return (
        // rendered component goes in here
      );
    }
Code language: JavaScript (javascript)

To see the toasts, we render the imported Toaster component anywhere in the app.

    import { Video, CloudinaryContext, Transformation } from "cloudinary-react";
    import { useRef, useEffect, useState } from "react";
    import { toast, Toaster } from "react-hot-toast";
    export default function IndexPage() {
      // component logic definitions go in here
    
      return (
        <div>
          <Toaster />
          Hello World.{" "}
          <CloudinaryContext cloudName="chuloo">
            <Video
              publicId="video-blog/cat"
              controls
              muted
              width="500px"
              innerRef={videoRef}
            />
          </CloudinaryContext>
        </div>
      );
    }
Code language: JavaScript (javascript)

Here’s what the final video looks like with the toasts on video events:

This post discussed using a video player in a Next.js app, hook into the video element’s native properties, events, and methods using useRef. We also handled UI changes on the page when a user fires video events.

Furthermore, you can handle data fetching and sending, or Ad display on your Next.js page using video events.

You may find these resources useful:

Back to top

Featured Post