Rooks
HooksUI & Layout

useIntersectionObserverRef

Returns a callback ref that forwards IntersectionObserver notifications to the latest callback.

About

useIntersectionObserverRef observes one attached element and forwards raw IntersectionObserverEntry records. Choose it when the callback needs ratios, root bounds, or other entry data and React does not need a separate inView state value.

Example

import { useCallback, useState } from "react";
import { useIntersectionObserverRef } from "rooks";

const thresholds = [0, 0.5, 1];

export default function IntersectionRatio() {
  const [ratio, setRatio] = useState(0);
  const onIntersection = useCallback<IntersectionObserverCallback>(
    (entries) => {
      setRatio(entries[0]?.intersectionRatio ?? 0);
    },
    []
  );
  const [targetRef] = useIntersectionObserverRef(onIntersection, {
    threshold: thresholds,
  });

  return (
    <section>
      <p aria-live="polite">Visible: {Math.round(ratio * 100)}%</p>
      <div
        ref={targetRef}
        style={{ minHeight: 160, border: "1px solid", padding: 16 }}
      >
        Scroll this element through the viewport.
      </div>
    </section>
  );
}

For frequently rerendering components, define a threshold array outside the component or memoize it so the array identity remains stable.

Parameters

ParameterTypeDefaultDescription
callbackIntersectionObserverCallback | undefinedrequired argumentReceives the observer entries. undefined is allowed and simply discards notifications.
optionsIntersectionObserverInitsee belowConfigures the observer root, margin, and thresholds.

Default options are root: null, rootMargin: "0px 0px 0px 0px", and threshold: [0, 1].

Return value

Returns a one-item tuple, [ref], containing a stable callback ref for an HTMLElement.

Behavior and lifecycle

The observer is created once a node attaches, even when callback is undefined. The latest callback is held in a ref, so changing only the callback does not recreate the observer. Changing the node, root, root margin, or threshold does recreate it. Cleanup calls disconnect() when the node changes or clears and when the component unmounts.

An inline threshold array has a new identity on each render and therefore recreates the observer; keep it stable when possible. Exceptions thrown by the supplied callback are not intercepted by the hook.

Constructor errors from invalid observer options are also allowed to propagate.

Compatibility and accessibility

No observer is created during server rendering. A client without IntersectionObserver needs a polyfill before the ref receives a node; the hook does not supply a fallback.

Intersection is visual information, not an accessibility state. Avoid removing essential or keyboard-focusable content solely because it is outside the viewport, and keep a usable path when observation is unavailable. See SSR and browser APIs.

  • useInViewRef converts notifications into a boolean state value.
  • useMeasure observes element dimensions with ResizeObserver.

On this page