Skip to content

useTabVisibility

Saurav-TB-Pandey edited this page Sep 18, 2026 · 1 revision

useTabVisibility

The useTabVisibility hook tracks whether the browser tab/document is currently active in real-time. Unlike basic document visibility listeners, it handles multi-monitor window blurring, mobile app freeze/resume (BFCache), and avoids false-positive "user left" triggers during initial hydration.


Usage

1. Minimum Configuration (Basic)

The simplest way to use useTabVisibility is to monitor the boolean isActive status or respond to basic activation/deactivation.

import { useTabVisibility } from 'react-hook-lab';

function ActiveTracker() {
  const { isActive } = useTabVisibility();

  return (
    <div>
      <p>Status: {isActive ? "Active" : "Inactive"}</p>
    </div>
  );
}

2. Common Usage (With Transition Callbacks & Media Pausing)

In real-world applications, you often want to pause resource-intensive tasks (e.g. video playback, animations, or WebSocket polling) when the user looks away or switches tabs.

import { useRef } from 'react';
import { useTabVisibility } from 'react-hook-lab';

function VideoPlayer() {
  const videoRef = useRef<HTMLVideoElement>(null);

  const { isActive, isVisible, isFocused, wasActive } = useTabVisibility({
    requireWindowFocus: true, // Default: true. User must be focused on this window
    onActivate: () => {
      console.log("Welcome back!");
      videoRef.current?.play();
    },
    onDeactivate: () => {
      console.log("User moved away from the tab");
      videoRef.current?.pause();
    },
  });

  return (
    <div>
      <video ref={videoRef} src="/media/sample.mp4" controls />
      <div>
        <span>{isActive ? "🟢 Active" : "🔴 Inactive"}</span>
        {isVisible && !isFocused && (
          <small> (Visible on screen, but unfocused in another app)</small>
        )}
      </div>
    </div>
  );
}

3. Advanced Usage (Multi-Monitor Analytics & Session Inactivity Tracking)

For security-sensitive apps, idle session timeouts, or detailed telemetry, use timestamps (lastActiveAt, lastInactiveAt) and wasActive to measure duration spent away without hydration false-positives.

import { useEffect } from 'react';
import { useTabVisibility } from 'react-hook-lab';

function SecureSessionMonitor() {
  const {
    isActive,
    wasActive,
    isVisible,
    isFocused,
    lastActiveAt,
    lastInactiveAt,
  } = useTabVisibility({
    requireWindowFocus: true,
    initialActive: true,
  });

  useEffect(() => {
    // wasActive is undefined until a real user transition occurs!
    if (!isActive && wasActive && lastInactiveAt) {
      console.log(`User left session at timestamp ${lastInactiveAt}`);
    } else if (isActive && wasActive === false && lastActiveAt && lastInactiveAt) {
      const awayDurationSeconds = Math.round((lastActiveAt - lastInactiveAt) / 1000);
      console.log(`User returned after being away for ${awayDurationSeconds}s`);

      if (awayDurationSeconds > 300) {
        // Prompt for re-authentication if away for more than 5 minutes
        promptReauth();
      }
    }
  }, [isActive, wasActive, lastActiveAt, lastInactiveAt]);

  return (
    <div>
      <h3>Security Gateway</h3>
      <p>Window active: {isActive ? "Yes" : "Locked / Away"}</p>
      <p>Screen visible: {isVisible ? "Yes" : "Hidden"}</p>
      <p>App focused: {isFocused ? "Yes" : "Unfocused"}</p>
    </div>
  );
}

API Reference

useTabVisibility(options?)

Parameters (UseTabVisibilityOptions)

Option Type Default Description
onActivate () => void undefined Callback fired exactly once for each inactive -> active transition.
onDeactivate () => void undefined Callback fired exactly once for each active -> inactive transition.
requireWindowFocus boolean true When true, the window must have user focus in addition to being visible. When false, document visibility alone determines activity.
initialActive boolean true Deterministic SSR baseline state before client-side hydration.

Return Value (UseTabVisibilityResult)

Property Type Description
isActive boolean true when the tab is currently active.
wasActive boolean | undefined Prior confirmed active state. Stays undefined until the first real transition occurs to prevent hydration false-positives.
isVisible boolean Direct document visibility (document.visibilityState === "visible").
isFocused boolean Direct document/window focus state.
lastActiveAt number | null Timestamp (ms) of the most recent confirmation of active state, or null.
lastInactiveAt number | null Timestamp (ms) of the most recent confirmation of inactive state, or null.

Clone this wiki locally