Why Page Visibility Matters
Modern web applications often continue running JavaScript code even when users aren't actively looking at the page. Whether it's an analytics tracker polling for data, a video player consuming resources, or a dashboard making API calls, unnecessary background processing wastes battery life, consumes data, and degrades performance.
The Page Visibility API provides a straightforward solution by letting your application detect when a page is actually visible to the user, enabling you to pause, throttle, or adjust behavior accordingly. This capability has become increasingly important as users open more tabs and switch between applications on mobile devices.
By respecting the user's attention and device resources, you build more responsible applications that provide a better experience while using fewer system resources. The Page Visibility API is a Baseline feature available across all modern browsers since 2015, making it a reliable tool for production applications.
Implementing visibility-aware patterns is an essential part of modern web development best practices, helping you create applications that are both performant and user-conscious.
Understanding Page Visibility States
The Page Visibility API introduces two key properties that let you check and monitor the visibility state of a document. These properties are accessed directly on the document object and provide both immediate state checks and ongoing change detection.
document.hidden Property
The document.hidden property returns a boolean value indicating whether the page is hidden from the user. When this property returns true, the page is not visible--either because the tab is in the background, the browser window is minimized, or the device's screen is off. This straightforward property is ideal for quick checks within your code logic, such as determining whether to initiate an action or continue a process.
document.visibilityState Property
The document.visibilityState property provides more detailed information about the document's current state. Modern browsers support two values: "visible" when at least part of the page is visible to the user, and "hidden" when the page is not visible. This approach allows for potential future extensions, though the practical difference between checking document.hidden and document.visibilityState === 'visible' is minimal in most applications.
These properties are read-only and update automatically as the visibility state changes. You can check them at any time to determine the current state, but for responding to changes, you'll want to listen for the dedicated visibilitychange event. Understanding these core JavaScript APIs is fundamental to building responsive web applications that adapt to user behavior.
The visibilitychange Event
The true power of the Page Visibility API lies in its ability to notify your application when visibility changes occur. The visibilitychange event fires on the document whenever the visibility state transitions between visible and hidden, whether due to tab switching, window minimization, or screen lock.
To respond to these events, you attach an event listener to the document object. The event itself doesn't carry special data--the current state is already available through the hidden and visibilityState properties. Your event handler simply needs to check these properties and respond accordingly.
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// Page is now hidden
handlePageHide();
} else {
// Page is now visible
handlePageShow();
}
});
The event fires synchronously when the visibility change occurs, ensuring your code can respond immediately. This is crucial for time-sensitive operations like pausing media playback or saving user progress before the page potentially unloads. By responding to the event rather than polling the state, your code remains efficient and only executes when necessary.
Common use cases for the Page Visibility API
Media Playback Control
Pause video and audio when users switch away from the tab to save bandwidth and battery while preventing audio interference.
Analytics Optimization
Pause analytics collection when the page is hidden to reduce server load and provide more accurate engagement metrics.
Resource Management
Pause polling intervals, reduce API call frequency, or batch requests when the page is not visible.
Battery Preservation
Reduce background processing to extend battery life on mobile devices with multiple open tabs.
Browser Throttling and Performance
Understanding how browsers handle background tabs helps you design effective visibility-aware applications. Modern browsers implement various performance optimizations for background tabs, and knowing these behaviors helps you avoid relying on incorrect assumptions about background code execution.
What Browsers Throttle
Browsers typically stop or throttle several types of operations in background tabs:
requestAnimationFramecallbacks stop firing for background tabs because there's no visible rendering to synchronize withsetTimeoutandsetIntervalcalls experience longer delays in background tabs- Budget-based throttling limits cumulative background execution time
Operations That Remain Unthrottled
Certain operations are exempt from browser throttling and continue running at full speed in background tabs:
- Tabs playing audio continue executing normally because interrupting audio would be a poor user experience
- WebSocket and WebRTC connections maintain their regular behavior to prevent timeouts
- IndexedDB operations continue unimpeded to prevent data loss or corruption
These browser-level optimizations mean that even without explicit visibility handling, background code runs less frequently. However, the Page Visibility API still provides value because it lets you make intentional decisions about what should and shouldn't continue in the background. For applications that rely heavily on real-time data and performance optimization, implementing visibility-aware patterns can significantly improve user experience and reduce unnecessary resource consumption.
Custom React Hook for Page Visibility
React hooks provide an elegant way to incorporate visibility handling into Next.js components. Creating a custom usePageVisibility hook encapsulates the visibility logic and makes it reusable across components.
import { useState, useEffect } from 'react';
function usePageVisibility() {
const [isVisible, setIsVisible] = useState(!document.hidden);
useEffect(() => {
const handleVisibilityChange = () => {
setIsVisible(!document.hidden);
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, []);
return isVisible;
}
This hook returns a boolean indicating visibility state and automatically handles event listener cleanup. Components can use it to conditionally enable or disable features based on visibility, keeping visibility logic separate from business logic.
Frequently Asked Questions
Sources
-
MDN Web Docs - Page Visibility API - Comprehensive documentation on the Page Visibility API including technical specifications, browser compatibility, and code examples.
-
web.dev - Using the Page Visibility API - Google's official developer resource providing practical introduction and code examples.