Visibility tracking

IntersectionObserver

Baseline widely available
  • Chrome58
  • Edge16
  • Firefox55
  • Safari12.1

Features it needs

These libraries all wrap the same browser API. IntersectionObserver watches an element and calls you back when it crosses a viewport threshold, without a scroll listener recalculating positions on every frame. Calling it directly removes a dependency for something the browser already does off the main thread.

When this applies

Running code when an element scrolls into or out of view, such as triggering analytics, infinite scroll, or an entrance animation.

The native approach

const observer = new IntersectionObserver(
  (entries) => {
    for (const entry of entries) {
      if (entry.isIntersecting) console.log("visible:", entry.target);
    }
  },
  { threshold: 0.5 },
);
observer.observe(document.querySelector("#target"));

MDN reference

When the dependency is still right

An answer that always says "the platform covers it" is worse than no answer. These are the cases where this one does not hold.

  • You want a framework hook's ergonomics, such as a boolean and a ref, rather than managing an observer instance yourself. The library is doing less work than it looks like at that point, but it's still less code at each call site.
  • You need to track intersection against a scrolling ancestor other than the viewport in a browser old enough to have inconsistent support for the root option.

Packages this covers