Join our Discord Community

React IntersectionObserver Hook

React useIntersectionObserver hook for element visibility detection. Track viewport intersections with configurable thresholds for Next.js apps.

Need help with lazy loading or infinite scroll?

Join our Discord community for help from other developers.


Ever tried to implement lazy loading or scroll animations and ended up wrestling with scroll event listeners and manual viewport calculations? You know the drill—measuring element positions, calculating visibility percentages, dealing with performance issues from constant scroll events. This free open source React useIntersectionObserver custom hook handles all that visibility detection complexity so you can focus on building smooth user experiences instead of reinventing intersection math in your React applications.

useIntersectionObserver showcase

Efficient element visibility tracking with native browser APIs:

Loading component...

This free open source React hook simplifies viewport intersection detection with TypeScript support for modern JavaScript applications. Whether you're building lazy loading systems, scroll animations, or analytics tracking in your Next.js projects, this React hook keeps your visibility logic performant.

Installation

npx shadcn@latest add https://www.shadcn.io/registry/use-intersection-observer.json
npx shadcn@latest add https://www.shadcn.io/registry/use-intersection-observer.json
pnpm dlx shadcn@latest add https://www.shadcn.io/registry/use-intersection-observer.json
bunx shadcn@latest add https://www.shadcn.io/registry/use-intersection-observer.json

Why most visibility detection implementations suck

Look, you could keep writing scroll event handlers and calculating element positions manually. But then you hit the performance wall—scroll events fire constantly, getBoundingClientRect is expensive, and you need to throttle everything to keep things smooth.

Most developers use scroll listeners with getBoundingClientRect() calculations, causing performance bottlenecks in React applications. Or they forget to throttle scroll events, leading to janky animations and poor user experience. Some skip cleanup entirely and wonder why their scroll handlers accumulate over time in TypeScript components.

This React hook uses the native Intersection Observer API under the hood in Next.js projects, which is specifically designed for efficient visibility tracking. The browser handles all the optimization, so you get smooth performance without the complexity.

Plus it handles all the edge cases—cleanup on unmount, browser compatibility, threshold configurations, freeze-once-visible behavior. No more memory leaks or janky scroll performance in JavaScript applications.

This free open source React hook manages efficient visibility detection while you focus on building features. Whether you're creating React applications, Next.js dashboards, or TypeScript components, reliable intersection tracking keeps your JavaScript development performant.

Features

  • Intersection Observer API with native browser support and automatic cleanup in React applications
  • Configurable thresholds supporting single values or arrays for precise detection in TypeScript components
  • Freeze on visible option to lock state once element becomes visible in Next.js projects
  • Custom root elements allowing observation relative to any container in JavaScript development
  • TypeScript support with complete type definitions and flexible destructuring for React frameworks
  • Performance optimized using efficient native browser APIs with minimal overhead in modern applications
  • Free open source designed for modern React development workflows

When you'll actually use this

Real talk—this isn't for every visibility check in React applications. Simple show/hide logic often works fine with CSS or basic state. But when you need performance-critical visibility detection or complex threshold logic, this React hook delivers in Next.js projects.

Perfect for:

  • Lazy loading - Images, videos, and content that loads when visible built with TypeScript
  • Scroll animations - Trigger effects when elements enter the viewport using React patterns
  • Analytics tracking - Monitor content exposure and engagement metrics in JavaScript applications
  • Infinite scroll - Detect when users reach the bottom of lists in React components
  • Performance optimization - Defer expensive operations until needed in Next.js applications
  • Progress indicators - Track reading progress and section visibility using TypeScript validation

API Reference

useIntersectionObserver

OptionTypeDefaultDescription
thresholdnumber | number[]0Visibility percentage needed to trigger (0-1)
rootElement | Document | nullnullContainer element for intersection calculation
rootMarginstring"0%"Margin around root element for intersection area
freezeOnceVisiblebooleanfalseLock intersection state once element becomes visible
initialIsIntersectingbooleanfalseInitial intersection state before observation
onChangefunctionundefinedCallback fired when intersection state changes

Return Value (Supports both tuple and object destructuring)

PropertyTypeDescription
ref(node?: Element | null) => voidRef callback to attach to target element
isIntersectingbooleanCurrent visibility state based on threshold
entryIntersectionObserverEntry | undefinedRaw intersection observer entry data

Common gotchas

Ref attachment requirement: The React hook won't work until you assign the ref to an actual element in your render in TypeScript components. Make sure the element exists and has dimensions.

Modern browser API limitation: Intersection Observer is supported in all modern browsers but won't work in Internet Explorer in React applications. The hook handles graceful degradation for older browsers.

Threshold percentage meanings: 0 means any pixel visible, 1 means completely visible in Next.js projects. Arrays let you track multiple visibility levels for complex animations.

Freeze behavior permanence: Once freezeOnceVisible is true and the element becomes visible, it stays visible even if scrolled away in JavaScript applications—perfect for one-time animations but can be confusing for debugging.

Root margin CSS syntax: rootMargin uses CSS margin syntax ("10px 20px") not JavaScript object syntax in React development. Incorrect syntax will cause unexpected behavior.

Observer instance sharing: Multiple elements with identical options share the same observer instance for performance in TypeScript projects, but different options create separate observers.

Questions you might have