---
title: "useIntersectionObserver – Element Hook Usage & Examples"
description: "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 [In"
canonical: https://reactuse.com/element/useintersectionobserver/
---

# 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](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and returns a [IntersectionObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)

`useIntersectionObserver` wraps the native [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/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 `IntersectionObserverInit` options (`root`, `rootMargin`, `threshold`) for precise control over when the callback fires.
- **Cleanup**: The observer is automatically disconnected on unmount. Call the returned `stop` function to disconnect manually if needed.
- See also `useElementVisibility` for a simplified boolean-only wrapper around this hook.

## Usage

```tsx live
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>
  );
};

```

%%API%%