Skip to main content

useIntersectionObserver

A React hook for observing when an element enters or exits the viewport using the Intersection Observer API.

npm install @plenty-hooks/use-intersection-observer

Showcase

import { useRef } from 'react';
import { useIntersectionObserver } from '@plenty-hooks/use-intersection-observer';

function LazyImage({ src, alt }: { src: string; alt: string }) {
const ref = useRef<HTMLDivElement>(null);
const [isVisible, setIsVisible] = useState(false);

useIntersectionObserver(
ref,
() => {
setIsVisible(true);
},
{ once: true }
);

return (
<div ref={ref}>
{isVisible ? <img src={src} alt={alt} /> : <div>Loading...</div>}
</div>
);
}

Triggering on Exit

You can configure the hook to trigger when an element exits the viewport:

import { useRef } from 'react';
import { useIntersectionObserver } from '@plenty-hooks/use-intersection-observer';

function TrackVisibility() {
const ref = useRef<HTMLDivElement>(null);

useIntersectionObserver(
ref,
(entry) => {
console.log('Element exited viewport');
},
{ trigger: 'exit' }
);

return <div ref={ref}>Track when I leave the viewport</div>;
}

Triggering on Both Enter and Exit

import { useRef } from 'react';
import { useIntersectionObserver } from '@plenty-hooks/use-intersection-observer';

function TrackBoth() {
const ref = useRef<HTMLDivElement>(null);

useIntersectionObserver(
ref,
(entry) => {
if (entry.isIntersecting) {
console.log('Entered viewport');
} else {
console.log('Exited viewport');
}
},
{ trigger: 'both' }
);

return <div ref={ref}>Track enter and exit</div>;
}

Global Configuration

Configure default options globally for all instances:

import { configUseIntersectionObserver } from '@plenty-hooks/use-intersection-observer';

// Configure once in your app entry point
configUseIntersectionObserver({
threshold: 0.5,
rootMargin: '10px',
});

API

useIntersectionObserver(ref, callback, options?)

Observes when an element enters or exits the viewport.

Parameters

  • ref: RefObject<T | null> - Ref to the element to observe
  • callback: (entry: IntersectionObserverEntry) => void - Callback to fire when the element intersects
  • options (optional): Configuration object with the following properties:
    • once?: boolean - If true, the callback will only be fired once (default: false)
    • enable?: boolean - If false, the observer will not be created (default: true)
    • rootTarget?: RefObject<Element | null> | Element | Document | null - The root element for the intersection observer
    • trigger?: 'enter' | 'exit' | 'both' - When to trigger the callback (default: 'enter')
    • rootMargin?: string - Margin around the root (e.g., '10px', '10px 20px')
    • threshold?: number | number[] - Threshold(s) at which to trigger callback (e.g., 0.5, [0, 0.5, 1])

Returns

void

configUseIntersectionObserver(options: Options)

Configures global default options for all useIntersectionObserver instances.

Parameters

  • options: Configuration object with the following properties:
    • once?: boolean - If true, the callback will only be fired once (default: false)
    • enable?: boolean - If false, the observer will not be created (default: true)
    • rootTarget?: RefObject<Element | null> | Element | Document | null - The root element for the intersection observer
    • trigger?: 'enter' | 'exit' | 'both' - When to trigger the callback (default: 'enter')
    • rootMargin?: string - Margin around the root
    • threshold?: number | number[] - Threshold(s) at which to trigger callback

Types

interface Options {
once?: boolean;
enable?: boolean;
rootTarget?: RefObject<Element | null> | IntersectionObserverInit['root'];
trigger?: 'enter' | 'exit' | 'both';
rootMargin?: IntersectionObserverInit['rootMargin'];
threshold?: IntersectionObserverInit['threshold'];
}