@@ -12,9 +12,6 @@ to tell you when an element enters or leaves the viewport. Contains both a
1212[ Hooks] ( #useinview-hook ) , [ render props] ( #render-props ) and
1313[ plain children] ( #plain-children ) implementation.
1414
15- ** Storybook Demo:**
16- [ https://react-intersection-observer.vercel.app ] ( https://react-intersection-observer.vercel.app )
17-
1815## Features
1916
2017- 🪝 ** Hooks or Component API** - With ` useInView ` it's easier than ever to
@@ -30,15 +27,11 @@ to tell you when an element enters or leaves the viewport. Contains both a
3027- 💥 ** Tiny bundle** - Around ** ~ 1.15kB** for ` useInView ` and ** ~ 1.6kB** for
3128 ` <InView> `
3229
33- ## Installation
34-
35- Install using [ Yarn] ( https://yarnpkg.com ) :
30+ [ ![ Open in StackBlitz] ( https://developer.stackblitz.com/img/open_in_stackblitz.svg )] ( https://stackblitz.com/github/thebuilder/react-intersection-observer )
3631
37- ``` sh
38- yarn add react-intersection-observer
39- ```
32+ ## Installation
4033
41- or NPM :
34+ Install the package with your package manager of choice :
4235
4336``` sh
4437npm install react-intersection-observer --save
@@ -65,8 +58,8 @@ Assign the `ref` to the DOM element you want to monitor, and the hook will
6558report the status.
6659
6760``` jsx
68- import React from ' react' ;
69- import { useInView } from ' react-intersection-observer' ;
61+ import React from " react" ;
62+ import { useInView } from " react-intersection-observer" ;
7063
7164const Component = () => {
7265 const { ref , inView , entry } = useInView ({
@@ -82,8 +75,6 @@ const Component = () => {
8275};
8376```
8477
85- [ ![ Edit useInView] ( https://codesandbox.io/static/img/play-codesandbox.svg )] ( https://codesandbox.io/s/useinview-ud2vo?fontsize=14&hidenavigation=1&theme=dark )
86-
8778### Render props
8879
8980To use the ` <InView> ` component, you pass it a function. It will be called
@@ -98,7 +89,7 @@ on `entry`, giving you access to all the details about the current intersection
9889state.
9990
10091``` jsx
101- import { InView } from ' react-intersection-observer' ;
92+ import { InView } from " react-intersection-observer" ;
10293
10394const Component = () => (
10495 < InView>
@@ -113,8 +104,6 @@ const Component = () => (
113104export default Component ;
114105```
115106
116- [ ![ Edit InView render props] ( https://codesandbox.io/static/img/play-codesandbox.svg )] ( https://codesandbox.io/s/inview-render-props-hvhcb?fontsize=14&hidenavigation=1&theme=dark )
117-
118107### Plain children
119108
120109You can pass any element to the ` <InView /> ` , and it will handle creating the
@@ -123,19 +112,17 @@ state in your own component. Any extra props you add to `<InView>` will be
123112passed to the HTML element, allowing you set the ` className ` , ` style ` , etc.
124113
125114``` jsx
126- import { InView } from ' react-intersection-observer' ;
115+ import { InView } from " react-intersection-observer" ;
127116
128117const Component = () => (
129- < InView as= " div" onChange= {(inView , entry ) => console .log (' Inview:' , inView)}>
118+ < InView as= " div" onChange= {(inView , entry ) => console .log (" Inview:" , inView)}>
130119 < h2> Plain children are always rendered . Use onChange to monitor state.< / h2>
131120 < / InView>
132121);
133122
134123export default Component ;
135124```
136125
137- [ ![ Edit InView plain children] ( https://codesandbox.io/static/img/play-codesandbox.svg )] ( https://codesandbox.io/s/inview-plain-children-vv51y?fontsize=14&hidenavigation=1&theme=dark )
138-
139126> ** Note** <br > When rendering a plain child, make sure you keep your HTML output
140127> semantic. Change the ` as ` to match the context, and add a ` className ` to style
141128> the ` <InView /> ` . The component does not support Ref Forwarding, so if you
@@ -149,7 +136,7 @@ Provide these as the options argument in the `useInView` hook or as props on the
149136** ` <InView /> ` ** component.
150137
151138| Name | Type | Default | Description |
152- | ------------------------ | --------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
139+ | ---------------------- | ------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
153140| ** root** | ` Element ` | ` document ` | The Intersection Observer interface's read-only root property identifies the Element or Document whose bounds are treated as the bounding box of the viewport for the element which is the observer's target. If the root is ` null ` , then the bounds of the actual document viewport are used. |
154141| ** rootMargin** | ` string ` | ` '0px' ` | Margin around the root. Can have values similar to the CSS margin property, e.g. ` "10px 20px 30px 40px" ` (top, right, bottom, left). Also supports percentages, to check if an element intersects with the center of the viewport for example "-50% 0% -50% 0%". |
155142| ** threshold** | ` number ` or ` number[] ` | ` 0 ` | Number between ` 0 ` and ` 1 ` indicating the percentage that should be visible before triggering. Can also be an array of numbers, to create multiple trigger points. |
@@ -166,7 +153,7 @@ Provide these as the options argument in the `useInView` hook or as props on the
166153The ** ` <InView /> ` ** component also accepts the following props:
167154
168155| Name | Type | Default | Description |
169- | -------------- | ------------------------------------------------------ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
156+ | ------------ | ---------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
170157| ** as** | ` IntrinsicElement ` | ` 'div' ` | Render the wrapping element as this element. Defaults to ` div ` . If you want to use a custom component, please use the ` useInView ` hook or a render prop instead to manage the reference explictly. |
171158| ** children** | ` ({ref, inView, entry}) => ReactNode ` or ` ReactNode ` | ` undefined ` | Children expects a function that receives an object containing the ` inView ` boolean and a ` ref ` that should be assigned to the element root. Alternatively pass a plain child, to have the ` <InView /> ` deal with the wrapping element. You will also get the ` IntersectionObserverEntry ` as ` entry ` , giving you more details. |
172159
@@ -213,8 +200,8 @@ few ideas for how you can use it.
213200You can wrap multiple ` ref` assignments in a single ` useCallback` :
214201
215202` ` ` jsx
216- import React , { useRef , useCallback } from ' react' ;
217- import { useInView } from ' react-intersection-observer' ;
203+ import React , { useRef , useCallback } from " react" ;
204+ import { useInView } from " react-intersection-observer" ;
218205
219206function Component (props ) {
220207 const ref = useRef ();
@@ -259,7 +246,7 @@ will emulate the real IntersectionObserver, allowing you to validate that your
259246components are behaving as expected.
260247
261248| Method | Description |
262- |-----------------------------------------------| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
249+ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
263250| ` mockAllIsIntersecting (isIntersecting)` | Set ` isIntersecting` on all current Intersection Observer instances. The value of ` isIntersecting` should be either a ` boolean` or a threshold between 0 and 1. |
264251| ` mockIsIntersecting (element, isIntersecting)` | Set ` isIntersecting` for the Intersection Observer of a specific ` element` . The value of ` isIntersecting` should be either a ` boolean` or a threshold between 0 and 1. |
265252| ` intersectionMockInstance (element)` | 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. |
@@ -285,11 +272,11 @@ Jest. Otherwise, you'll need to manually setup/reset the mocking in either the
285272individual tests, or a [setup file](https://vitest.dev/config/#setupfiles).
286273
287274` ` ` js
288- import { vi , beforeEach , afterEach } from ' vitest' ;
275+ import { vi , beforeEach , afterEach } from " vitest" ;
289276import {
290277 setupIntersectionMocking ,
291278 resetIntersectionMocking ,
292- } from ' react-intersection-observer/test-utils' ;
279+ } from " react-intersection-observer/test-utils" ;
293280
294281beforeEach (() => {
295282 setupIntersectionMocking (vi .fn );
@@ -321,7 +308,7 @@ were you actively import `react-intersection-observer/test-utils`.
321308**test-setup.js**
322309
323310` ` ` js
324- import { defaultFallbackInView } from ' react-intersection-observer' ;
311+ import { defaultFallbackInView } from " react-intersection-observer" ;
325312
326313defaultFallbackInView (true ); // or `false` - whichever consistent behavior makes the most sense for your use case.
327314` ` `
@@ -334,21 +321,21 @@ Vitest.
334321
335322` ` ` js
336323module .exports = {
337- setupFilesAfterEnv: [' react-intersection-observer/test-utils' ],
324+ setupFilesAfterEnv: [" react-intersection-observer/test-utils" ],
338325};
339326` ` `
340327
341328### Test Example
342329
343330` ` ` js
344- import React from ' react' ;
345- import { screen , render } from ' @testing-library/react' ;
346- import { useInView } from ' react-intersection-observer' ;
331+ import React from " react" ;
332+ import { screen , render } from " @testing-library/react" ;
333+ import { useInView } from " react-intersection-observer" ;
347334import {
348335 mockAllIsIntersecting ,
349336 mockIsIntersecting ,
350337 intersectionMockInstance ,
351- } from ' react-intersection-observer/test-utils' ;
338+ } from " react-intersection-observer/test-utils" ;
352339
353340const HookComponent = ({ options }) => {
354341 const { ref , inView } = useInView (options);
@@ -359,37 +346,37 @@ const HookComponent = ({ options }) => {
359346 );
360347};
361348
362- test (' should create a hook inView' , () => {
363- render (< HookComponent/ > );
349+ test (" should create a hook inView" , () => {
350+ render (< HookComponent / > );
364351
365352 // This causes all (existing) IntersectionObservers to be set as intersecting
366353 mockAllIsIntersecting (true );
367- screen .getByText (' true' );
354+ screen .getByText (" true" );
368355});
369356
370- test (' should create a hook inView with threshold' , () => {
371- render (< HookComponent options= {{ threshold: 0.3 }}/ > );
357+ test (" should create a hook inView with threshold" , () => {
358+ render (< HookComponent options= {{ threshold: 0.3 }} / > );
372359
373360 mockAllIsIntersecting (0.1 );
374- screen .getByText (' false' );
361+ screen .getByText (" false" );
375362
376363 // Once the threshold has been passed, it will trigger inView.
377364 mockAllIsIntersecting (0.3 );
378- screen .getByText (' true' );
365+ screen .getByText (" true" );
379366});
380367
381- test (' should mock intersecing on specific hook' , () => {
382- render (< HookComponent/ > );
383- const wrapper = screen .getByTestId (' wrapper' );
368+ test (" should mock intersecing on specific hook" , () => {
369+ render (< HookComponent / > );
370+ const wrapper = screen .getByTestId (" wrapper" );
384371
385372 // Set the intersection state on the wrapper.
386373 mockIsIntersecting (wrapper, 0.5 );
387- screen .getByText (' true' );
374+ screen .getByText (" true" );
388375});
389376
390- test (' should create a hook and call observe' , () => {
391- const { getByTestId } = render (< HookComponent/ > );
392- const wrapper = getByTestId (' wrapper' );
377+ test (" should create a hook and call observe" , () => {
378+ const { getByTestId } = render (< HookComponent / > );
379+ const wrapper = getByTestId (" wrapper" );
393380 // Access the `IntersectionObserver` instance for the wrapper Element.
394381 const instance = intersectionMockInstance (wrapper);
395382
@@ -422,7 +409,7 @@ application can correctly handle all your observers firing either `true` or
422409You can set the fallback globally:
423410
424411` ` ` js
425- import { defaultFallbackInView } from ' react-intersection-observer' ;
412+ import { defaultFallbackInView } from " react-intersection-observer" ;
426413
427414defaultFallbackInView (true ); // or 'false'
428415` ` `
@@ -431,8 +418,8 @@ You can also define the fallback locally on `useInView` or `<InView>` as an
431418option. This will override the global fallback value.
432419
433420` ` ` jsx
434- import React from ' react' ;
435- import { useInView } from ' react-intersection-observer' ;
421+ import React from " react" ;
422+ import { useInView } from " react-intersection-observer" ;
436423
437424const Component = () => {
438425 const { ref , inView , entry } = useInView ({
@@ -461,7 +448,7 @@ yarn add intersection-observer
461448Then import it in your app:
462449
463450` ` ` js
464- import ' intersection-observer' ;
451+ import " intersection-observer" ;
465452` ` `
466453
467454If you are using Webpack (or similar) you could use
@@ -474,8 +461,8 @@ like this:
474461 * Do feature detection, to figure out which polyfills needs to be imported.
475462 **/
476463async function loadPolyfills () {
477- if (typeof window .IntersectionObserver === ' undefined' ) {
478- await import (' intersection-observer' );
464+ if (typeof window .IntersectionObserver === " undefined" ) {
465+ await import (" intersection-observer" );
479466 }
480467}
481468` ` `
@@ -488,13 +475,13 @@ IntersectionObserver instances. This allows you to handle more advanced use
488475cases, where you need full control over when and how observers are created.
489476
490477` ` ` js
491- import { observe } from ' react-intersection-observer' ;
478+ import { observe } from " react-intersection-observer" ;
492479
493480const destroy = observe (element, callback, options);
494481` ` `
495482
496483| Name | Type | Required | Description |
497- |--------------| ----------------------------| ----------| ------------------------------------------------------------ |
484+ | ------------ | -------------------------- | -------- | ---------------------------------------------------------- |
498485| **element** | ` Element ` | true | DOM element to observe |
499486| **callback** | ` ObserverInstanceCallback` | true | The callback function that Intersection Observer will call |
500487| **options** | ` IntersectionObserverInit` | false | The options for the Intersection Observer |
@@ -507,29 +494,13 @@ order to destroy the observer again.
507494> how instances are created.
508495
509496[package-url]: https://npmjs.org/package/react-intersection-observer
510-
511497[npm-version-svg]: https://img.shields.io/npm/v/react-intersection-observer.svg
512-
513- [npm-minzip-svg]:
514- https://img.shields.io/bundlephobia/minzip/react-intersection-observer.svg
515-
516- [bundlephobia-url]:
517- https://bundlephobia.com/result?p=react-intersection-observer
518-
498+ [npm-minzip-svg]: https://img.shields.io/bundlephobia/minzip/react-intersection-observer.svg
499+ [bundlephobia-url]: https://bundlephobia.com/result?p=react-intersection-observer
519500[license-image]: http://img.shields.io/npm/l/react-intersection-observer.svg
520-
521501[license-url]: LICENSE
522-
523502[downloads-image]: http://img.shields.io/npm/dm/react-intersection-observer.svg
524-
525- [downloads-url]:
526- http://npm-stat.com/charts.html?package=react-intersection-observer
527-
528- [test-image]:
529- https://github.com/thebuilder/react-intersection-observer/workflows/Test/badge.svg
530-
531- [test-url]:
532- https://github.com/thebuilder/react-intersection-observer/actions?query=workflow%3ATest
533-
534- [test-utils-url]:
535- https://github.com/thebuilder/react-intersection-observer/blob/master/src/test-utils.ts
503+ [downloads-url]: http://npm-stat.com/charts.html?package=react-intersection-observer
504+ [test-image]: https://github.com/thebuilder/react-intersection-observer/workflows/Test/badge.svg
505+ [test-url]: https://github.com/thebuilder/react-intersection-observer/actions?query=workflow%3ATest
506+ [test-utils-url]: https://github.com/thebuilder/react-intersection-observer/blob/master/src/test-utils.ts
0 commit comments