{"id":15190,"library":"react-intersection-observer-hook","title":"React Intersection Observer Hook","description":"The `react-intersection-observer-hook` package provides declarative React hooks, specifically `useIntersectionObserver` and `useTrackVisibility`, to interact with the browser's native Intersection Observer API. It simplifies detecting when a React component enters or exits the viewport, enabling features like lazy loading, infinite scrolling, and triggering animations. The current stable version is 4.0.2, with active development focusing on modern React compatibility, demonstrated by its recent update for React 19 in v4.0.0. Releases are frequent, addressing bugs and improving API ergonomics. Key differentiators include a dedicated `useTrackVisibility` for simpler boolean visibility checks, explicit `rootRef` handling for scrollable containers, and robust support for both ES Modules and CommonJS environments since v3.0.0, ensured through modern bundling practices.","status":"active","version":"4.0.2","language":"javascript","source_language":"en","source_url":"https://github.com/onderonur/react-intersection-observer-hook","tags":["javascript","react","react-hooks","intersection-observer","on-screen","visibility","typescript"],"install":[{"cmd":"npm install react-intersection-observer-hook","lang":"bash","label":"npm"},{"cmd":"yarn add react-intersection-observer-hook","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-intersection-observer-hook","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for all React hooks. Version 4.x explicitly requires React 19+ for ref cleanup functions.","package":"react","optional":false},{"reason":"Required for rendering and attaching refs in React applications. Version 4.x explicitly requires React 19+.","package":"react-dom","optional":false}],"imports":[{"note":"This package is ESM-first since v3.0.0. Use ES module `import` syntax. `require()` might cause issues with some bundlers.","wrong":"const useIntersectionObserver = require('react-intersection-observer-hook');","symbol":"useIntersectionObserver","correct":"import { useIntersectionObserver } from 'react-intersection-observer-hook';"},{"note":"`useTrackVisibility` is a named export, not a default export. Ensure correct named import syntax.","wrong":"import useTrackVisibility from 'react-intersection-observer-hook';","symbol":"useTrackVisibility","correct":"import { useTrackVisibility } from 'react-intersection-observer-hook';"},{"note":"Import types separately using `import type` for better type-checking and bundle optimization in TypeScript projects.","symbol":"IntersectionObserverHookArgs","correct":"import type { IntersectionObserverHookArgs } from 'react-intersection-observer-hook';"}],"quickstart":{"code":"import React from 'react';\nimport { useTrackVisibility } from 'react-intersection-observer-hook';\n\nfunction MyTrackedComponent() {\n  const [ref, { isVisible, entry, rootRef }] = useTrackVisibility({\n    // Optionally, track visibility only once\n    // once: true,\n    // Customize intersection threshold (0.0 to 1.0)\n    threshold: 0.5,\n    // Add margin around the root (e.g., '10px 20px 30px 40px')\n    // rootMargin: '0px 0px -50px 0px',\n  });\n\n  // For a scrollable container (e.g., div with overflow-y: scroll),\n  // attach rootRef to the container. Otherwise, it defaults to the viewport.\n  const ScrollableContainer = React.forwardRef((props, forwardedRef) => (\n    <div ref={forwardedRef} style={{ height: '300px', overflowY: 'scroll', border: '1px solid gray' }}>\n      {props.children}\n    </div>\n  ));\n\n  return (\n    <div style={{ height: '1000px', padding: '200px 0' }}>\n      <p>Scroll down to see the tracked element.</p>\n      <ScrollableContainer ref={rootRef}>\n        <div style={{ height: '400px', background: 'lightblue', margin: '100px 0' }}></div>\n        <div ref={ref} style={{ height: '200px', background: isVisible ? 'lightgreen' : 'lightcoral', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n          <h2>Element is {isVisible ? 'visible!' : 'not visible.'}</h2>\n          {entry && <p>Intersection Ratio: {entry.intersectionRatio.toFixed(2)}</p>}\n        </div>\n        <div style={{ height: '400px', background: 'lightblue', margin: '100px 0' }}></div>\n      </ScrollableContainer>\n    </div>\n  );\n}\n\nexport default MyTrackedComponent;\n","lang":"typescript","description":"This example demonstrates how to use `useTrackVisibility` to detect when a component enters or leaves the viewport, changing its background color. It also shows how to specify a custom scrollable container using `rootRef`."},"warnings":[{"fix":"Upgrade your project's React and React-DOM peer dependencies to v19 or higher, or explicitly install `react-intersection-observer-hook@^3` if you need to remain on an older React version.","message":"Versions `v4.0.0` and above are designed for React 19 and utilize its new cleanup functions for refs. Users on older React versions (e.g., React 18 or earlier) should continue using `v3.x` to avoid compatibility issues.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Ensure your bundler (e.g., Webpack, Rollup, Vite) is configured to handle modern ES Modules and CommonJS interoperability correctly. Check `publint` and `Are the Types Wrong` documentation if module resolution issues persist.","message":"Version `v3.0.0` introduced significant internal changes, including a migration to a monorepo structure, bundling with tsup, and stricter ESM/CJS compliance. While this improves module support, users with highly customized or older build setups might encounter resolution issues.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"If tracking multiple elements, use separate `useIntersectionObserver` instances for each, or manage multiple refs manually with a single observer if advanced control is needed.","message":"The `ref` callback returned by `useIntersectionObserver` and `useTrackVisibility` must be attached to *only one* element at a time. Attaching it to multiple elements will result in unexpected behavior or only track the last assigned element.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use the `rootRef` callback from the hook: `<ScrollableContainer ref={rootRef}><SomeComponent ref={ref}/></ScrollableContainer>`.","message":"When specifying a scrollable container as the `root`, the `rootRef` callback returned by the hook should be used to assign the container element, rather than attempting to pass a `root` DOM element directly as an argument to the hook.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Unless targeting extremely old browsers, avoid including `IntersectionObserver` polyfills to reduce bundle size and potential conflicts.","message":"As of `v4.0.2`, the README no longer suggests using a polyfill for `IntersectionObserver`. Modern browsers widely support the API, and polyfills are rarely needed unless targeting legacy environments.","severity":"deprecated","affected_versions":">=4.0.2"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Always guard access to `entry` properties, e.g., `const isVisible = entry && entry.isIntersecting;`.","cause":"The `entry` object from `useIntersectionObserver` or `useTrackVisibility` is `undefined` during the initial render before the observer has reported an intersection.","error":"TypeError: Cannot read properties of undefined (reading 'isIntersecting')"},{"fix":"Ensure the hook is called within a React function component or another custom hook, and verify `react` and `react-dom` peer dependencies match your project's React version (especially for v4 requiring React 19).","cause":"Using `useIntersectionObserver` or `useTrackVisibility` outside a React function component or custom hook, or having multiple React versions in your dependency tree.","error":"Error: Invalid hook call. Hooks can only be called inside of the body of a function component."},{"fix":"Check your `tsconfig.json` (`moduleResolution`, `module`), `package.json` (`type`), and bundler configuration. Ensure you're using a modern bundler setup that supports `exports` field in `package.json`.","cause":"Your build tool or Node.js environment is struggling to resolve the package's module exports, potentially due to `v3.0.0`'s bundling changes and stricter ESM/CJS output.","error":"Module not found: Can't resolve 'react-intersection-observer-hook'"}],"ecosystem":"npm"}