Skip to content

Instantly share code, notes, and snippets.

@AnishLushte07
Last active April 21, 2024 08:02
Show Gist options
  • Save AnishLushte07/4d436dac2fac1ed6f9cae8a6a88eeb68 to your computer and use it in GitHub Desktop.
Save AnishLushte07/4d436dac2fac1ed6f9cae8a6a88eeb68 to your computer and use it in GitHub Desktop.
ReactJS custom hook for page visibility change. Track tabs and window switch.
/*
* This react hook tracks page visibility using browser page visibility api.
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
*
* Use: const pageVisibilityStatus = usePageVisibility();
* Return type: boolean
*/
import { useState, useEffect } from 'react';
let hidden, visibilityChange;
if (typeof document.hidden !== 'undefined') {
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document.msHidden !== 'undefined') {
hidden = 'msHidden';
visibilityChange = 'msvisibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
}
export default function usePageVisibility() {
const [visibilityStatus, setVisibilityStatus] = React.useState(document[hidden]);
React.useEffect(() => {
function handleVisibilityChange() {
setVisibilityStatus(document[hidden]);
}
document.addEventListener(visibilityChange, handleVisibilityChange);
return () => {
document.removeEventListener(visibilityChange, handleVisibilityChange);
}
}, []);
return visibilityStatus;
}
@estebangarviso
Copy link

estebangarviso commented Aug 2, 2023

For Nextjs 13:

// use-page-visibility.ts
'use client'

import { useState, useEffect } from 'react'

type Hidden = keyof Pick<Document, 'hidden' | 'msHidden' | 'webkitHidden'>
type VisibilityChange = keyof Pick<
  DocumentEventMap,
  'visibilitychange' | 'msvisibilitychange' | 'webkitvisibilitychange'
>
let hidden: Hidden | undefined
let visibilityChange: VisibilityChange | undefined

export default function usePageVisibility() {
  if (typeof document?.hidden !== 'undefined') {
    hidden = 'hidden'
    visibilityChange = 'visibilitychange'
  } else if (typeof document?.msHidden !== 'undefined') {
    hidden = 'msHidden'
    visibilityChange = 'msvisibilitychange'
  } else if (typeof document?.webkitHidden !== 'undefined') {
    hidden = 'webkitHidden'
    visibilityChange = 'webkitvisibilitychange'
  }
  const initialHidden = hidden ? document[hidden] : false
  const [visibilityStatus, setVisibilityStatus] = useState<boolean>(initialHidden)

  useEffect(() => {
    const handleVisibilityChange = () => {
      if (hidden) setVisibilityStatus(document[hidden])
    }
    if (visibilityChange) document.addEventListener(visibilityChange, handleVisibilityChange, false)
    return () => {
      if (visibilityChange) document.removeEventListener(visibilityChange, handleVisibilityChange)
    }
  }, [])

  return visibilityStatus
}
// global.d.ts
interface DocumentEventMap {
  msvisibilitychange: Event
  webkitvisibilitychange: Event
}
interface Document {
  msHidden: boolean
  webkitHidden: boolean
}

@dberardo-com
Copy link

setVisibilityStatus(document[hidden]);

should be

setVisibilityStatus(!document[hidden]);

@qexxep
Copy link

qexxep commented Apr 21, 2024

I have a question. Why do not use document.visibilityState?
Is it because of cross-browser compatibility?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment