useIntersectionObserverLoading saved progress…

useIntersectionObserver

"Is this element on screen?" powers a huge amount of UI: lazy-loading images as they scroll into view, infinite-scroll sentinels, fade-in-on-reveal animations, viewability analytics. The efficient way to answer it is the IntersectionObserver API — the browser watches an element against a viewport and calls you back when its visibility crosses a threshold, with none of the scroll-listener jank. useIntersectionObserver wraps that API into a hook.

Implement useIntersectionObserver(elementRef, options). Observe elementRef.current, keep the latest IntersectionObserverEntry in state, and return it (so callers read entry?.isIntersecting). Support threshold, root, rootMargin, and a freezeOnceVisible flag that stops observing after the element first appears.

Signature

function useIntersectionObserver(elementRef, {
  threshold = 0, root = null, rootMargin = '0%', freezeOnceVisible = false,
}) {
  // returns the latest IntersectionObserverEntry (or undefined)
}

Examples

const ref = useRef(null);
const entry = useIntersectionObserver(ref, { threshold: 0.5 });
const isVisible = entry?.isIntersecting;
<div ref={ref}>{isVisible ? <Chart /> : <Placeholder />}</div>
// One-shot reveal: freeze so it never flips back to hidden.
const entry = useIntersectionObserver(ref, { freezeOnceVisible: true });

Notes

  • Observe in an effect — create new IntersectionObserver(cb, options), observe(node), and disconnect() in the cleanup.
  • Store the entry — the callback's first entry goes into state; return it so the component re-renders on visibility change.
  • Guard — do nothing if elementRef.current is null or IntersectionObserver isn't available (older browsers / SSR).
  • freezeOnceVisible — once isIntersecting is true, stop observing and keep the last entry — ideal for lazy-load and reveal-once.
Loading editor…