useIntersectionObserver
React sensor hook that tracks the changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport. Uses the Intersection Observer API and returns a IntersectionObserverEntry
useIntersectionObserver wraps the native Intersection Observer API in a React-friendly interface. It observes a target element and fires a callback with the full IntersectionObserverEntry array whenever the element’s intersection with a root container changes. The hook returns a stop function to disconnect the observer early.
When to Use
- Implementing infinite scroll by detecting when a sentinel element enters the viewport
- Lazy-loading images or heavy components only when they become visible
- Triggering scroll-based animations or analytics events at specific intersection thresholds
Notes
- Configurable: Supports all standard
IntersectionObserverInitoptions (root,rootMargin,threshold) for precise control over when the callback fires. - Cleanup: The observer is automatically disconnected on unmount. Call the returned
stopfunction to disconnect manually if needed. - See also
useElementVisibilityfor a simplified boolean-only wrapper around this hook.
Usage
Live Editor
function Demo() { const Spacer = () => ( <div style={{ width: "200px", height: "300px", }} /> ); const options = { root: null, rootMargin: "0px", threshold: 1, }; const intersectionRef = useRef(null); const [entry, setEntry] = useState<IntersectionObserverEntry[]>([]); const stop = useIntersectionObserver( intersectionRef, (entry) => { setEntry(entry); }, options ); return ( <div style={{ width: "400px", height: "400px", overflow: "scroll", }} > Scroll me <Spacer /> <button onClick={() => { stop(); }} > stop observe </button> <div ref={intersectionRef} style={{ width: "100px", height: "100px", padding: "20px", background: "var(--c-hj-b)", }} > {entry[0] && entry[0].intersectionRatio < 1 ? "Obscured" : "Fully in view"} </div> <Spacer /> </div> ); };
Result
API
useIntersectionObserver
Returns
() => void: stop listening function
Arguments
| Argument | Description | Type | DefaultValue |
|---|---|---|---|
| target | dom element | BasicTarget<Element> (Required) | - |
| callback | callback | IntersectionObserverCallback (Required) | - |
| options | options passed to IntersectionObserver | IntersectionObserverInit | undefined | - |
BasicTarget
export type BasicTarget<T extends TargetType = Element> = (() => TargetValue<T>) | TargetValue<T> | MutableRefObject<TargetValue<T>>;
TargetValue
type TargetValue<T> = T | undefined | null;
TargetType
type TargetType = HTMLElement | Element | Window | Document | EventTarget;