← Back to all snippets
JAVASCRIPT

Custom useOnScreen Hook for Element Visibility Detection

A React custom hook that uses the Intersection Observer API to detect if a specified DOM element is visible within the viewport, ideal for lazy loading or animations.

import { useState, useEffect, useRef } from 'react';

const useOnScreen = (options) => {
  const ref = useRef(null);
  const [isIntersecting, setIntersecting] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      setIntersecting(entry.isIntersecting);
    }, options);

    if (ref.current) {
      observer.observe(ref.current);
    }

    return () => {
      if (ref.current) { // Ensure ref.current is still available during cleanup
        observer.unobserve(ref.current);
      }
      observer.disconnect();
    };
  }, [options]); // Re-run effect if options change

  return [ref, isIntersecting];
};

export default useOnScreen;

// How to use:
// import useOnScreen from './useOnScreen';
// function ScrollAnimationComponent() {
//   const [myRef, isVisible] = useOnScreen({ threshold: 0.5 }); // 50% visible to trigger
//   return (
//     <div style={{ height: '100vh', background: 'lightgray' }}>
//       Scroll down to see the magic!
//     </div>
//     <div
//       ref={myRef}
//       style={{
//         height: '100vh',
//         background: isVisible ? 'lightblue' : 'pink',
//         transition: 'background 0.5s ease-in-out',
//         display: 'flex',
//         justifyContent: 'center',
//         alignItems: 'center',
//         fontSize: '2em'
//       }}
//     >
//       {isVisible ? 'I am visible!' : 'Scroll more!'}
//     </div>
//     <div style={{ height: '100vh', background: 'lightgray' }}>
//       End of page.
//     </div>
//   );
// }
How it works: This hook detects when a specified DOM element enters or exits the viewport. It utilizes `useRef` to target the element and `useEffect` to instantiate an `IntersectionObserver`. The observer's callback updates the `isIntersecting` state when the target element's visibility changes according to the provided `options` (e.g., `threshold`, `rootMargin`). This is invaluable for implementing features like lazy loading images, animating elements as they scroll into view, or tracking user engagement without costly scroll event listeners. The cleanup function ensures the observer is properly disconnected.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs