Changelog
July 10, 2026
What’s Changed
- chore: update github actions by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/754
- Add support for
scrollMarginoption for intersection observers by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/753
Full Changelog: https://github.com/thebuilder/react-intersection-observer/compare/v10.0.3...v10.1.0
February 18, 2026
What’s Changed
- prevent callback skipping with triggerOnce and merged refs by @djk01281 in https://github.com/thebuilder/react-intersection-observer/pull/747
New Contributors
- @djk01281 made their first contribution in https://github.com/thebuilder/react-intersection-observer/pull/747
Full Changelog: https://github.com/thebuilder/react-intersection-observer/compare/v10.0.2...v10.0.3
January 15, 2026
What’s Changed
- Add npm package size badge to README by @jantimon in https://github.com/thebuilder/react-intersection-observer/pull/740
- feat: bump dependencies by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/741
- Fix React 17 webpack build error for useInsertionEffect by @Copilot in https://github.com/thebuilder/react-intersection-observer/pull/744
New Contributors
- @jantimon made their first contribution in https://github.com/thebuilder/react-intersection-observer/pull/740
Full Changelog: https://github.com/thebuilder/react-intersection-observer/compare/v10.0.0...v10.0.2
October 28, 2025
Based on the great work in #718 by @jantimon - This release adds the new useOnInView hook.
✨ New
useOnInViewhook — a no-re-render alternative touseInViewthat delivers(inView, entry)to your callback while returning a ref you can attach to any element. Designed for tracking, analytics, and other side effect heavy workloads where state updates are unnecessary.IntersectionChangeEffect/IntersectionEffectOptionstypes — exported helper types that describe the new hook’s callback and options surface.- Storybook playground + documentation — new story, README section, and JSDoc example demonstrating how to use
useOnInView.
⚠️ Breaking Changes
useInView,useOnInView, and<InView>now ignore the browser’s initialinView === falseemission foronChangeevents, so handlers only fire once a real visibility change occurs, while still reporting all subsequent enter/leave transitions.
🧪 Testing
- Added a dedicated Vitest suite for
useOnInView, covering thresholds,triggerOnce,skiptoggling, merged refs, and multiple observers on the same node.
What’s Changed
- chore: update package url in package.json by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/721
- build(deps-dev): bump vite from 6.2.0 to 6.2.5 by @dependabot[bot] in https://github.com/thebuilder/react-intersection-observer/pull/724
- build(deps-dev): bump vite from 6.2.5 to 6.2.7 by @dependabot[bot] in https://github.com/thebuilder/react-intersection-observer/pull/727
- Fix minor grammatical issue in documentation intro by @Akshay-Vs in https://github.com/thebuilder/react-intersection-observer/pull/728
- Remove bundlephobia badge from README by @Copilot in https://github.com/thebuilder/react-intersection-observer/pull/731
- Update dependencies by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/737
- feat: implement the useOnInView hook by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/738
New Contributors
- @Akshay-Vs made their first contribution in https://github.com/thebuilder/react-intersection-observer/pull/728
- @Copilot made their first contribution in https://github.com/thebuilder/react-intersection-observer/pull/731
Full Changelog: https://github.com/thebuilder/react-intersection-observer/compare/v9.16.0...v10.0.0
March 5, 2025
What’s Changed
- ci: drop semantic release flow by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/719
- Correctly detect global testing framework by @thebuilder in https://github.com/thebuilder/react-intersection-observer/pull/720
Full Changelog: https://github.com/thebuilder/react-intersection-observer/compare/v9.15.1...v9.16.0
January 21, 2025
January 14, 2025
December 30, 2024
December 14, 2024
September 4, 2024
July 11, 2024
July 11, 2024
July 11, 2024
June 5, 2024
May 3, 2024
April 29, 2024
April 28, 2024
April 28, 2024
April 8, 2024
February 22, 2024
February 9, 2024
February 5, 2024
February 1, 2024
January 31, 2024
November 9, 2023
June 28, 2023
June 20, 2023
June 17, 2023
9.5.0 (2023-06-17)
Breaking changes
This release switches the build tool to tsup, in order for the package to support the use client directive. Hopefully it shouldn’t have an impact on usage, but changing build output, always carries a slight risk of some tooling breaking.
- Changes the export file names. If you relied on importing files directly, then you’ll need to change the imports.
- Drops bundling the “umd” version. If anyone was relying on this, let me know.
Features
June 1, 2023
February 23, 2023
February 8, 2023
November 15, 2022
July 22, 2022
9.4.0 (2022-07-22)
This release fixes https://github.com/thebuilder/react-intersection-observer/issues/572
It’s now possible (not recommended) to use inline functions for ref methods. This will still cause extra rerenders, but you will not get into a state of infinite loops.
Bug Fixes
- optimize re-renders in useInView (a3e2be5)
Features
- rewrite internals to use setState for
ref(776caa6)
June 30, 2022
June 23, 2022
June 15, 2022
June 15, 2022
June 15, 2022
June 14, 2022
June 2, 2022
June 2, 2022
May 28, 2022
April 25, 2022
April 21, 2022
9.0.0 (2022-04-21)
This release is mainly to fix an issue with the exports not being properly tree-shaken.
Features
Size of exports
After tree shaking, this is the current size impact of the exports, as reported by size-limit.
InView- 1.6 kB with all dependencies, minified and gzippeduseInView- 1.13 kB with all dependencies, minified and gzippedobserve- 835 B with all dependencies, minified and gzipped
BREAKING CHANGES
- Removed the
defaultexport of theInViewcomponent. Use the namedInViewimport instead
-import InView from 'react-intersection-observer
+import { InView } from 'react-intersection-observer
April 12, 2022
8.34.0 (2022-04-12)
Features
Breaking changes
- This removes the old
tagprop from<InView>, that was deprecated byassome years ago. If you haven’t changed it, this could break your build. The fix would be to replace all instances oftagwithas. - Changed the type of
asfrom the oldReactTypetoElementType. This would only be a problem if you are still using the old version of the React Types.
December 15, 2021
December 9, 2021
8.33.0 (2021-12-09)
Features
This is solution for #495 that adds support for a fallbackInView value.
You can set the fallback globally:
import { defaultFallbackInView } from 'react-intersection-observer';
defaultFallbackInView(true); // or 'false'
You can also define the fallback locally on useInView or <InView> as an
option. This will override the global fallback value.
import React from 'react';
import { useInView } from 'react-intersection-observer';
const Component = () => {
const { ref, inView, entry } = useInView({
fallbackInView: true,
});
return (
<div ref={ref}>
<h2>{`Header inside viewport ${inView}.`}</h2>
</div>
);
};
November 25, 2021
November 23, 2021
November 19, 2021
October 25, 2021
August 27, 2021
May 14, 2021
April 19, 2021
November 24, 2020
November 12, 2020
November 11, 2020
November 3, 2020
November 1, 2020
October 19, 2020
September 28, 2020
September 24, 2020
September 11, 2020
September 10, 2020
September 9, 2020
September 8, 2020
September 7, 2020
September 7, 2020
8.28.0 (2020-09-07)
Features
Details
This is a rewrite of the internal handling of IntersectionObservers, alongside general refactoring and alignment of the code.
- Breaking change: Remove default export for the InView component
- Remove outdated fixes for the initial IntersectionObserver browser implementation. These were needed 3 years ago, to ensure all browsers acted according to the spec
- Support multiple observers on the same element. Closes #340
- Rewrite
tests, so they use test-utils to properly mock the IntersectionObserver instances - Switch to microbundle for compiling
- Add initial IntersectionObserver v2 support. Closes #368
IntersectionObserver v2 🧪
The new v2 implementation of IntersectionObserver extends the original API, so you can track if the element is covered by another element or has filters applied to it. Useful for blocking clickjacking attempts or tracking ad exposure.
To use it, you’ll need to add the new trackVisibility and delay options.
When you get the entry back, you can then monitor if isVisible is true.
const TrackVisible = () => {
const { ref, entry } = useInView({ trackVisibility: true, delay: 100 });
return <div ref={ref}>{entry?.isVisible}</div>;
};
This is still a very new addition, so check
caniuse for current browser
support. If trackVisibility has been set, and the current browser doesn’t
support it, a fallback has been added to always report isVisible as true.
It’s not added to the TypeScript lib.d.ts file yet, so you will also have to
extend the IntersectionObserverEntry with the isVisible boolean.
August 20, 2020
August 19, 2020
April 24, 2020
February 26, 2020
- fix: the inView state could be reset with triggerOnce #311 (#312) a18d398
https://github.com/thebuilder/react-intersection-observer/compare/v8.26.0...v8.26.1
February 23, 2020
- Fix inView not reset when ref removed #303 (#306) 0c450ce
- Fix Lazy Load Image example (#304) 211228a
https://github.com/thebuilder/react-intersection-observer/compare/v8.25.3...v8.26.0
February 17, 2020
- chore: upgrade dependencies 14afafb
- Update test-utils.ts (#302) e31086c
- chore(package): update @testing-library/jest-dom to version 5.0.0 (#292) 5ed2118
- Update @types/jest to the latest version 🚀 (#297) 83be44b
- chore(package): update husky to version 4.0.2 (#290) de43354
https://github.com/thebuilder/react-intersection-observer/compare/v8.25.2...v8.25.3
November 27, 2019
- chore: upgrade dependencies 23b1d51
- fix: Mock additional intersection properties (#286) aeae955
- chore: upgrade dependencies and readme 9348aab
- docs: add Edit on Codesandbox badge to hook 4129884
- Create ci.json (#283) fcf7f59
- Fixed grammatical errors in README (#282) 45d13b9
- Update README.md f37cc6f
- Update README.md 1c84b58
https://github.com/thebuilder/react-intersection-observer/compare/v8.25.1...v8.25.2
October 17, 2019
- fix: move tiny-invariant to dependencies a6c965e
https://github.com/thebuilder/react-intersection-observer/compare/v8.25.0...v8.25.1
October 17, 2019
- build: optimize the rollup build 3cadc06
https://github.com/thebuilder/react-intersection-observer/compare/v8.24.2...v8.25.0
September 9, 2019
- fix: don’t add onChange prop to the plain children container (#272) 4d88ea2
- Fix recipe for triggering animations (#271) 31a890b
- chore(package): update babel-eslint to version 10.0.3 (#268) 4af02e7
- chore: upgrade dependencies b20abcc
- chore(package): update @typescript-eslint/eslint-plugin to version 2.0.0 (#261) a5061a5
- Changed typo const supportsNativeLoading to supportsLazyLoading (#265) fdc4e63
- Add codesandbox example 3fe0710
- Merge remote-tracking branch ‘origin/master’ e037bdc
- docs: update the recipes c6d1f48
https://github.com/thebuilder/react-intersection-observer/compare/v8.24.1...v8.24.2
July 15, 2019
- chore: upgrade dependencies 4734187
- refactor: switch to useCallback for setting node ref b31487b
- build(deps): bump lodash-es from 4.17.11 to 4.17.14 (#253) 828cfa9
- Add note about constant threshold array (#251) 2f65d87
- chore: upgrade dependencies 7961292
- Update eslint-plugin-import to the latest version 🚀 (#245) 8a77732
- Update eslint to the latest version 🚀 (#244) f5fe897
- Update babel-eslint to the latest version 🚀 (#242) 7319667
- Minor JS typos in hook recipes (#243) b473795
- Minor JS typos in hook recipes (#243) f71d5c0
- Update babel-eslint to the latest version 🚀 (#242) c627551
- Minor JS typos in hook recipes (#243) 5f40a96
- Minor JS typos in hook recipes (#243) d06da8c
- readme: fix typo 0ca244a
- build: remove np from devDependencies 6fa9cc1
- build: add an improved release script 5806034
- refactor: make types for Observer readonly cb7e9f6
- build: upgrade the build command daf6805
- chore: upgrade dependencies, including switching to the @testing-library/react namespace and TypeScript 3.51 e268f18
- Update Recipes.md 3029aa8
- docs: fix typos c91f718
- Update Recipes.md e1fdeff
- Merge remote-tracking branch ‘origin/master’ 197ccce
- docs: update the documentation, fixing typos and add recipes fe6d30f
- chore(package): update rollup-plugin-terser to version 5.0.0 (#230) 755e92e
- Update eslint-plugin-import to the latest version 🚀 (#234) 5ec08c5
- Update rollup-plugin-commonjs to the latest version 🚀 (#227) e71f220
- Update intersection-observer to the latest version 🚀 (#226) 6593532
- Update package.json 9b743f9
- don’t use yarn for np. Might not work correctly with contents 0a1b726
- Update package.json 1a3f5d7
https://github.com/thebuilder/react-intersection-observer/compare/v8.23.1...v8.24.0
April 29, 2019
This release restructures how the project is published to npm. Instead of publishing the entire project, it just publishes the content of the dist directory.
This is only a breaking change, if you were importing files from the src or dist directory before.
If you do run into an issue with imports, it should be fixed by importing directly from react-intersection-observer.
March 25, 2019
This release tweaks the Typescript typings for the PlainChildren version, so it should be more generic.
March 14, 2019
- refactor: change the Map loop to forEach (#200) 831ca3a
https://github.com/thebuilder/react-intersection-observer/compare/v8.22.2...v8.22.3
March 13, 2019
Hooks were broken in last release - they would never trigger when they left the viewport. 😳
https://github.com/thebuilder/react-intersection-observer/compare/v8.22.1...v8.22.2
March 12, 2019
This fixes #197 and allows you to actually import the file into Jest.
March 11, 2019
Potential breaking change #195
Change for the <InView>
Previously, the initial callback would trigger a state update, even if the element was still outside the viewport.
This update changes the behavior, so it won’t trigger new state update before the element enters the viewport.
If you used the IntersectionObserverEntry during that first callback, it will no longer work. The use case for this, is most likely to determine if the element started outside the viewport.
Workaround
As a workaround, you can use the onChange callback, since this will still be called everytime.
March 6, 2019
This releases is focused on helping you when writing tests.
In order to write meaningful tests, the IntersectionObserver needs to be
mocked. If you are writing your tests in Jest, you can use the included
test-utils.js. It mocks the IntersectionObserver, and includes a few methods
to assist with faking the inView state.
test-utils.js
Import the methods from react-intersection-observer/test-utils.
mockAllIsIntersecting(isIntersecting:boolean)
Set the isIntersecting on all current IntersectionObserver instances.
mockIsIntersecting(element:Element, isIntersecting:boolean)
Set the isIntersecting for the IntersectionObserver of a specific element.
intersectionMockInstance(element:Element): IntersectionObserver
Call the intersectionMockInstance method with an element, to get the (mocked)
IntersectionObserver instance. You can use this to spy on the observe and
unobserve methods.
Test Example
import React from 'react'
import { render } from 'react-testing-library'
import { useInView } from 'react-intersection-observer'
import { mockAllIsIntersecting } from 'react-intersection-observer/test-utils'
const HookComponent = ({ options }) => {
const [ref, inView] = useInView(options)
return <div ref={ref}>{inView.toString()}</div>
}
test('should create a hook inView', () => {
const { getByText } = render(<HookComponent />)
mockAllIsIntersecting(true)
getByText('true')
})
February 10, 2019
So now that Hooks have been out in the wild for a week, a few issues are starting to pop up. Especially relating to how refs are handled (#162). To fix this, the current API needs to be changed.
New useInView API:
const [ref, inView, entry] = useInView(options)
If you are already using the hook, then you will need to update your code, by changing:
const Component = () => {
const ref = useRef()
const inView = useInView(ref, {
threshold: 0,
})
return (
<div ref={ref}>
...
</div>
)
}
Into:
const Component = () => {
const [ref, inView] = useInView({
threshold: 0,
})
return (
<div ref={ref}>
...
</div>
)
}
Removed
- The
useIntersectionObserverhook was removed in favor of theuseInViewhook.
Tests
Tests have been rewritten using react-testing-library. Before they were messing with the internals of the components to fake updates. It also just works with the new hooks.
January 30, 2019
I decided to switch the project from Flow to TypeScript. This should ensure the TypeScript definitions match the actual implementation, without the need to manually sync the index.d.tsfile.
In the process, i’ve rewritten some of the internals, but it shouldn’t affect the actual API.
A documentation site has also been created using docz: https://react-intersection-observer.now.sh
Breaking changes
- The deprecated
rendermethod has been removed - Make sure you usechildreninstead. - Instead of returning just
intersectionRatio, you now getentrythat contains the entireIntersectionObserverEntryelement. If you’re relying onintersectionRatio, you should change your code toentry.intersectionRatio. rootIdhas been removed - An idea for each unique root is now auto generated. This always felt like temporary solution, until i implemented a smarter way.- Flow types have been removed.
January 8, 2019
This release exposes the intersectionRatio, giving you a bit more insight into what triggered an update.
import { InView } from 'react-intersection-observer'
const Component = () => (
<InView>
{({ inView, ref, intersectionRatio }) => (
<div ref={ref}>
<h2>{`Header inside viewport ${inView} at ${intersectionRatio}`}</h2>
</div>
)}
</InView>
)
export default Component
See #123
November 28, 2018
This release enables support for the useInView(ref, options) hook. The library will work fine with older versions of React, as long as you don’t use the execute the hook.
import { useRef } from 'react'
import { useInView } from 'react-intersection-observer'
const Component = () => {
const ref = useRef()
const inView = useInView(ref, {
/* Optional options */
threshold: 0,
})
return (
<div ref={ref}>
<h2>{`Header inside viewport ${inView}.`}</h2>
</div>
)
}
The release also refactors the Rollup build, which should result in a more optimized bundle.
September 13, 2018
This is a fix for #119
September 4, 2018
This release updates Babel and Rollup, and publishes the new output files.
June 28, 2018
Due to popular demand (#91), I’ll keep support for rendering plain children inside the <Observer />.
This release just removes the deprecation flag. You don’t need to change anything.
June 26, 2018
Looking at how i’m currently using react-intersection-observer, and how render props have been adapted by React, this release moves all rendering to to the children prop.
The way to use the component is to forward the ref to your outer element, giving you full control over the DOM.
import Observer from 'react-intersection-observer'
const Component = () => (
<Observer>
{({ inView, ref }) => (
<div ref={ref}>
<h2>{`Header inside viewport ${inView}.`}</h2>
</div>
)}
</Observer>
)
export default Component
⚠️ Breaking changes
- Deprecated
renderprop - Deprecated
tagprop - Deprecated
childas React.Node
They will still work for now, but you’ll get a deprecation warning unless NODE_ENV is production.
If you are currently using render, you can move the method directly to children.
May 20, 2018
Switch the build system to Rollup, so the package now contains an umd, CommonJS and ES optimized build. 🎉
This shouldn’t change anything if you are already using the package, but if you imported the files in dist directly then that won’t work anymore
May 14, 2018
No more wrapping div element! render now gives complete control over the rendering, making it easier to use while keeping HTML semantic
import Observer from 'react-intersection-observer'
const Component = () => (
<Observer
render={({ inView, ref }) => (
<div ref={ref}>
<h2>{`Header inside viewport ${inView}.`}</h2>
</div>
)}
/>
)
export default Component
⚠️ Breaking change
- Removed
innerRef - Changed
rendercallback arguments
This release breaks the render prop, so it differs from the child as function method.
If you used the render method before, and you were happy with, you can move the function to children.
Otherwise, you’ll need to handle the new ref and assign it to a HTMLElement.
Old way
<Observer render={inView => <h2>Inview {inView}</h2>} />
New way
<Observer render={({inView, ref}) => <div ref=ref><h2>Inview {inView}</h2></div>} />
January 4, 2018
This fixes #53
December 21, 2017
The render prop pattern recently became a popular replacement for the child as function pattern.
Previously the render prop on react-intersection-observer, was handled differently from children so it only rendered when the element was inside the viewport.
⚠️ Breaking change
If you were using the render prop before, you need to handle when to render the content.
Old way
<Observer render={() => <div>Only rendered when in viewport</div>} />
New way
<Observer render={inView => inView ? <div>Only rendered when in viewport</div> : null} />
November 14, 2017
Thanks to @Kovensky for correcting the definitions.
November 10, 2017
Thanks to @forabi