8
Hooks

useIntersectionObserver

A hook that detects when elements enter or exit the viewport using the Intersection Observer API.

useIntersectionObserver

The useIntersectionObserver hook provides an easy way to detect when an element enters or exits the viewport using the browser’s Intersection Observer API. This is useful for implementing lazy loading, infinite scrolling, animations on scroll, and tracking element visibility.

Item 1
Hidden
Item 2
Hidden
Item 3
Hidden
Item 4
Hidden
Item 5
Hidden
Item 6
Hidden
Item 7
Hidden
Item 8
Hidden
Item 9
Hidden
Item 10
Hidden
1
2
3
4
5
6
7
8
9
10

Installation

Install the useIntersectionObserver hook using:

npx axionjs-ui add hook use-intersection-observer

File Structure

use-intersection-observer.ts

Parameters

PropTypeDefault
root
Element | null
null (browser viewport)
rootMargin
string
0px
threshold
number | number[]
0
triggerOnce
boolean
false
skip
boolean
false

Return Value

PropTypeDefault
ref
RefObject<T>
-
isIntersecting
boolean
-
entry
IntersectionObserverEntry | null
-

Examples

Lazy Loading Images

Load images only when they scroll into view to improve page load performance:

Scroll down to load images
Image will load when scrolled into view
Image will load when scrolled into view
Image will load when scrolled into view
Image will load when scrolled into view
Image will load when scrolled into view

Animations on Scroll

Trigger animations when elements scroll into view:

Scroll down to see elements animate in

Section 1

This content fades in when it enters the viewport, enhancing the user experience with subtle animations triggered by scrolling.

Section 2

This content fades in when it enters the viewport, enhancing the user experience with subtle animations triggered by scrolling.

Section 3

This content fades in when it enters the viewport, enhancing the user experience with subtle animations triggered by scrolling.

Section 4

This content fades in when it enters the viewport, enhancing the user experience with subtle animations triggered by scrolling.

Section 5

This content fades in when it enters the viewport, enhancing the user experience with subtle animations triggered by scrolling.

Tracking Visibility for Analytics

Monitor when elements are viewed for analytics purposes:

function TrackableSection({ id, title, onView }) {
  const [ref, isIntersecting] = useIntersectionObserver({
    threshold: 0.5,
    triggerOnce: true,
  });
  
  useEffect(() => {
    if (isIntersecting) {
      // Track that this section was viewed
      onView({ id, title, timestamp: new Date() });
    }
  }, [isIntersecting, id, title, onView]);
  
  return (
    <section ref={ref}>
      <h2>{title}</h2>
      {/* Section content */}
    </section>
  );
}
 
function AnalyticsPage() {
  const trackView = (data) => {
    // Send to analytics service
    analytics.trackSectionView(data);
  };
  
  return (
    <div>
      <TrackableSection 
        id="intro" 
        title="Introduction" 
        onView={trackView} 
      />
      <TrackableSection 
        id="features" 
        title="Features" 
        onView={trackView} 
      />
      <TrackableSection 
        id="pricing" 
        title="Pricing" 
        onView={trackView} 
      />
    </div>
  );
}

Use Cases

  • Lazy Loading: Load images, videos, or components only when needed
  • Infinite Scrolling: Load more content when the user reaches the bottom
  • Animations on Scroll: Trigger animations when elements enter the viewport
  • Visibility Tracking: Monitor which elements are visible for analytics
  • Auto-playing Media: Start/stop videos or audio when in/out of view
  • Smart Navigation: Highlight navigation items based on visible sections
  • Delayed Loading: Defer non-critical content loading until needed
  • Performance Optimization: Reduce initial page load time and resources

Intersection Observer Options

Threshold

The threshold option controls at what percentage of the target’s visibility the observer’s callback should be executed:

  • 0 (default): Callback is invoked as soon as even 1 pixel is visible
  • 1.0: Callback is invoked when 100% of the target is visible
  • Array of values: Callback is invoked for each threshold crossed
// Track different visibility thresholds
const [ref, isIntersecting, entry] = useIntersectionObserver({
  threshold: [0, 0.25, 0.5, 0.75, 1],
});
 
// Get exact visibility percentage
const visibilityPercentage = entry ? Math.round(entry.intersectionRatio * 100) : 0;

Root Margin

The rootMargin option adds margin around the root element, effectively increasing or decreasing the area considered for intersection:

// Start observing when element is 200px from entering the viewport
const [ref, isIntersecting] = useIntersectionObserver({
  rootMargin: "200px 0px 0px 0px", // top, right, bottom, left
});

Trigger Once

The triggerOnce option stops observing the element after it’s been intersected once:

// Perfect for one-time animations or lazy loading
const [ref, isIntersecting] = useIntersectionObserver({
  triggerOnce: true,
});

Accessibility

When implementing features with the Intersection Observer, consider these accessibility best practices:

  • Ensure content is accessible even if JavaScript is disabled
  • Provide proper fallbacks for browsers that don’t support Intersection Observer
  • Don’t rely solely on scroll events for critical functionality
  • For lazy-loaded images, always provide appropriate alt text
  • Consider users who may have disabled animations (prefers-reduced-motion)
  • Avoid content that suddenly appears, which can be disorienting

Browser Support

The Intersection Observer API is supported in all modern browsers. For older browsers, consider using a polyfill or the hook’s built-in fallback behavior, which sets isIntersecting to true when the API isn’t available.

Best Practices

  • Use the triggerOnce option for one-time actions like animations or lazy loading
  • Set appropriate threshold values based on your use case
  • Use rootMargin to start loading content before it’s actually visible
  • Keep observed elements simple to avoid performance issues
  • Use the full entry data for advanced calculations like position or timing
  • Combine with CSS transitions/animations for smooth visual effects
  • Unobserve elements when they’re no longer needed

On this page