React Hook to play a video with Intersection Observer

How to use a custom React hook to auto-play a video with Intersection Observer when it becomes visible and pause when it goes out of view.

I was building my wife’s website and she wanted to play a video clip as a background with some text overlaying the video. I knew I did not want to play the video on page load, but only when it became visible to the user.

With Intersection Observer, I was able to accomplish exactly that.

Before you start the tutorial, you can read about React Custom Hooks in the official documentation if you are unfamiliar with the concept.

The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport.

From MDN

Going by that definition, we need some wrapper containing the video element so that we will have a section wrapping the video in our React component.

Component importing the React Hook

const MyComponent = () => {
  const [containerRef, videoRef] = useVideoAutoPlayback({
    root: null,
    rootMargin: '0px',
    threshold: 0.1,
  });

  return (
    <section ref={containerRef}>
      <video playsinline muted loop ref={videoRef}>
        <source type="video/mp4" src=""myvideo.mp4" />
      </video>
    </section>
  );
}

In lines 2-6 we are calling the custom React Hook useVideoAutoPlayback. This hook accepts an options object, which is the properties for Intersection Observer API – more on this later.

useVideoAutoPlayback returns two Refs, which we use for the section (wrapper) and video elements.

Intersection Observer

The following is the Intersection Observer’s signature

let observer = new IntersectionObserver(callback, options);

That options object is what we pass to useVideoAutoPlayback. It takes the following properties:

  • root: The element used as the viewport for checking the visibility of the target. Must be the ancestor of the target.
  • rootMargin: Margin around the root. The values can be percentages.
  • threshold: Either a single number or an array of numbers that indicate at what percentage of the target’s visibility the observer’s callback should be executed.

The above definitions from MDN

React Hook with the Intersection Observer

import { useRef, useEffect } from 'react';

const useVideoAutoPlayback = options => {
  const containerRef = useRef(null);
  const videoRef = useRef(null);

  const cb = entries => {
    const [entry] = entries;

    if (entry.isIntersecting) videoRef.current.play();
    else videoRef.current.pause();
  };

  useEffect(() => {
    const observer = new IntersectionObserver(cb, options);

    if (containerRef.current) observer.observe(containerRef.current);

    return () => {
      if (containerRef.current) observer.unobserve(containerRef.current);
    };
  }, [containerRef, options]);

  return [containerRef, videoRef];
};

export { useVideoAutoPlayback };

In lines 4-5, we create the Refs which we return to the component in line 24.

In line 15 we create an observer object. We’ll go back to the callback function later.

Line 17 we “register” the target element. In our case, this is the section element.

Then we do clean-up in line 20.

Now we go back to the callback function (cb). The function receives an array of entries, and we extract the first one. From there we check if the target element is intersecting (entry.isIntersecting), then we play the video (videoRef.current.play()), otherwise, we pause.

entry.isIntersecting will give us true when the element becomes visible (intersects), and false when it is no longer visible.

Intersection Observer In Action

Intersection Observer In Action
Intersection Observer In Action

In the above GIF the video starts playing when it becomes visible, but only after 1% (or threshold of 0.1) of the video element is shown. If I see less than 1% of the video element, as you can see, the video pauses.

Real-life demo and repo

Visit my wife’s website to see the implementation and scroll down to see the video playing and pausing.

You can access the GitHub repo ArtistStatement.js component: https://github.com/esausilva/andrea-silva-design.

In conclusion

By following this technique, we save data for the user, not unnecessarily loading the video when the user is not even looking at it.

To learn more about the Intersection Observer API, visit MDN docs.

If you liked this short tutorial, share it on your social media and you can follow me on Twitter or LinkedIn.


Consider giving back by getting me a coffee (or a couple) by clicking the following button:

[bottomads][/bottomads]

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.