How to Use the Page Visibility API and Custom React Hooks to Improve User Experience

Learn how to enhance user experience with the Page Visibility API and custom React hooks.

Zachary Lee
Bits and Pieces

--

Photo by Nikita Kostrykin on Unsplash

As modern browsers support tabbed browsing, webpages might remain in the background, hidden from users. The Page Visibility API offers insights into whether a webpage is visible or not, making it a valuable resource for developers. In this article, we will comprehensively discuss the Page Visibility API, and its use cases, and demonstrate how to create a custom React Hook for more efficient usage.

Visibility Change Event

When a user minimizes the window or switches to another tab, the Page Visibility API sends a visibilitychange event to inform listeners about the change in the page's state. We can handle this event and perform actions based on the visibility state, such as pausing a video when the page is hidden from view.

Using the Page Visibility API

The Page Visibility API is part of the document object. We can use it by checking the document.hidden property(described as “historical”) or the document.visibilityState property(recommend), both of which are read-only. To monitor changes in both properties, we can listen to the visibilitychange event.

Example: Pausing a Video

In this example, we will pause a video when switching to a different tab. First, we add the HTML code for the video:

<video id="myVideo" width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
Your browser does not support the video tag.
</video>

Next, in our JavaScript code, we listen to the visibilitychange event:

document.addEventListener("visibilitychange", function() {
const video = document.getElementById("myVideo");
if (document.visibilityState === "hidden") {
video.pause();
} else if (document.visibilityState === "visible") {
video.play();
}
});

In our event listener callback, we pause the video when the visibilityState is not 'visible'. This means the user cannot see the tab either because they navigated away, minimized the window, or turned the screen off. Alternatively, you can set the event handler to the onvisibilitychange property of document.

document.visibilityState can take on these values:

  • visible: The page is visible to the user as a foreground tab
  • hidden: The page is not visible to the user, either because it's in the background, minimized, or the device's screen is off

Creating a Custom React Hook

Now that we have covered the Page Visibility API basics, let’s create a custom React Hook to make it even more convenient to use within a React application.

Creating the usePageVisibility Hook

First, let’s create a new usePageVisibility Hook that utilizes the useState and useEffect Hooks to manage the page visibility state:

import { useState, useEffect } from 'react';

function usePageVisibility() {
const [isVisible, setIsVisible] = useState(!document.hidden);

useEffect(() => {
function handleVisibilityChange() {
setIsVisible(document.visibilityState === 'visible');
}

document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);

return isVisible;
}

This custom Hook returns a boolean value representing the visibility of the page. It sets up an event listener for the visibilitychange event and updates the isVisible state accordingly.

What if you could reuse this custom hook across projects with a simple npm i @bit/your-username/use-page-visibility? You could do just that using an open-source toolchain like Bit.

Find out more:

Usage Example

Now, let’s see how we can use our custom usePageVisibility Hook in a React component to pause and play a video:


import { useRef, useEffect } from 'react';
import usePageVisibility from './usePageVisibility';

function VideoPlayer({ src }) {
const videoRef = useRef();
const isVisible = usePageVisibility();

useEffect(() => {
const video = videoRef.current;
if (isVisible) {
video.play();
} else {
video.pause();
}
}, [isVisible]);

return (
<video ref={videoRef} width="320" height="240" controls>
<source src={src} type="video/mp4" />
Your browser does not support the video tag.
</video>
);
}

Example: Managing Notifications

Similarly, we can use the usePageVisibility Hook to manage notifications in our application. For instance, if we have a chat application that displays new message notifications:

import React, { useState, useEffect } from 'react';
import usePageVisibility from './usePageVisibility';

function ChatApp() {
const [messages, setMessages] = useState([]);
const [newMessageCount, setNewMessageCount] = useState(0);
const isVisible = usePageVisibility();

useEffect(() => {
// Subscribe to new messages from the chat API
function handleNewMessage(message) {
setMessages((prevMessages) => [...prevMessages, message]);
if (!isVisible) {
setNewMessageCount((prevCount) => prevCount + 1);
}
}
// Subscribe to the chat API
const unsubscribe = chatApi.subscribe(handleNewMessage);
return () => {
// Unsubscribe from the chat API when the component is unmounted
unsubscribe();
};
}, [isVisible]);

return <div>{/* Render the chat messages and new message count here */}</div>;
}

Conclusion

The Page Visibility API is a valuable tool for detecting the visibility state of a webpage. By listening to the visibilitychange event and using the document.visibilityState property, developers can perform various actions depending on the page's visibility. Additionally, creating a custom React Hook, such as usePageVisibility, allows for more convenient and efficient use of the API within React applications.

Thanks for reading. If you like such stories and want to support me, please consider becoming a Medium member. It costs $5 per month and gives unlimited access to Medium content. I’ll get a little commission if you sign up via my link.

Build React Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--