Convert Figma logo to code with AI

researchgate logoreact-intersection-observer

React component for the Intersection <Observer /> API

1,125
60
1,125
20

Top Related Projects

React implementation of the Intersection Observer API to tell you when an element enters or leaves the viewport.

Sensor component for React that notifies you when it goes in or out of the window viewport.

😎 🖥️ React hook to monitor an element enters or leaves the viewport (or another element).

React components for efficiently rendering large lists and tabular data

Quick Overview

React Intersection Observer is a React component that utilizes the Intersection Observer API to detect when an element enters or leaves the viewport. It provides a simple and efficient way to implement lazy loading, infinite scrolling, or any other functionality that depends on element visibility.

Pros

  • Easy to use with a declarative API
  • Highly performant, using the native Intersection Observer API
  • Supports both hooks and render props patterns
  • Customizable with various options like threshold and root margin

Cons

  • Requires polyfill for older browsers that don't support Intersection Observer API
  • Limited to React applications
  • May have a slight learning curve for developers unfamiliar with Intersection Observer concepts

Code Examples

  1. Basic usage with hooks:
import { useInView } from 'react-intersection-observer';

function Component() {
  const { ref, inView } = useInView();

  return (
    <div ref={ref}>
      {inView ? 'Element is visible' : 'Element is not visible'}
    </div>
  );
}
  1. Using render props:
import { InView } from 'react-intersection-observer';

function Component() {
  return (
    <InView>
      {({ inView, ref }) => (
        <div ref={ref}>
          {inView ? 'Element is visible' : 'Element is not visible'}
        </div>
      )}
    </InView>
  );
}
  1. Customizing options:
import { useInView } from 'react-intersection-observer';

function Component() {
  const { ref, inView } = useInView({
    threshold: 0.5,
    triggerOnce: true,
    rootMargin: '0px 0px -100px 0px',
  });

  return (
    <div ref={ref}>
      {inView ? 'Element is at least 50% visible' : 'Element is not visible'}
    </div>
  );
}

Getting Started

  1. Install the package:

    npm install react-intersection-observer
    
  2. Import and use in your React component:

    import { useInView } from 'react-intersection-observer';
    
    function MyComponent() {
      const { ref, inView } = useInView();
    
      return (
        <div ref={ref}>
          {inView ? 'I am visible' : 'I am not visible'}
        </div>
      );
    }
    
  3. Optionally, add a polyfill for older browsers:

    import 'intersection-observer';
    

Competitor Comparisons

React implementation of the Intersection Observer API to tell you when an element enters or leaves the viewport.

Pros of react-intersection-observer

  • More actively maintained with frequent updates
  • Larger community support and usage
  • Comprehensive documentation and examples

Cons of react-intersection-observer

  • Slightly larger bundle size
  • May have more features than needed for simple use cases

Code Comparison

react-intersection-observer:

import { useInView } from 'react-intersection-observer';

const Component = () => {
  const { ref, inView } = useInView();
  return <div ref={ref}>{inView ? 'Visible' : 'Not visible'}</div>;
};

react-intersection-observer:

import { IntersectionObserver } from 'react-intersection-observer';

const Component = () => (
  <IntersectionObserver>
    {({ inView, ref }) => (
      <div ref={ref}>{inView ? 'Visible' : 'Not visible'}</div>
    )}
  </IntersectionObserver>
);

Both libraries provide similar functionality for detecting element visibility using the Intersection Observer API. The main differences lie in the API design and additional features. react-intersection-observer offers a more modern hook-based approach, while react-intersection-observer uses a render prop pattern. The choice between the two depends on personal preference and specific project requirements.

Sensor component for React that notifies you when it goes in or out of the window viewport.

Pros of react-visibility-sensor

  • Simpler API with fewer configuration options, making it easier to use for basic visibility detection
  • Supports older browsers that don't have IntersectionObserver API
  • Provides more granular control over when the visibility callback is triggered

Cons of react-visibility-sensor

  • Less performant than IntersectionObserver-based solutions, especially for multiple elements
  • Requires more manual setup for advanced use cases like lazy loading
  • May cause more frequent re-renders due to its implementation

Code Comparison

react-visibility-sensor:

<VisibilitySensor onChange={(isVisible) => console.log(isVisible)}>
  <div>Content to detect</div>
</VisibilitySensor>

react-intersection-observer:

const { ref, inView } = useInView();
return <div ref={ref}>{inView && 'Content is visible'}</div>;

react-intersection-observer offers a more modern and performant approach using the IntersectionObserver API, while react-visibility-sensor provides a simpler API with broader browser support. The choice between the two depends on specific project requirements, target browsers, and performance considerations. react-intersection-observer is generally recommended for newer projects due to its better performance and more idiomatic React usage with hooks.

😎 🖥️ React hook to monitor an element enters or leaves the viewport (or another element).

Pros of react-cool-inview

  • More comprehensive API with additional features like onChange callback and unobserve option
  • Better TypeScript support with more detailed type definitions
  • Smaller bundle size, potentially improving performance

Cons of react-cool-inview

  • Less widely adopted compared to react-intersection-observer
  • Documentation could be more extensive and provide more examples

Code Comparison

react-intersection-observer:

import { useInView } from 'react-intersection-observer';

const Component = () => {
  const [ref, inView] = useInView();
  return <div ref={ref}>{inView ? 'In view' : 'Not in view'}</div>;
};

react-cool-inview:

import useInView from 'react-cool-inview';

const Component = () => {
  const { ref, inView } = useInView();
  return <div ref={ref}>{inView ? 'In view' : 'Not in view'}</div>;
};

Both libraries offer similar basic functionality, but react-cool-inview provides a more feature-rich API with additional options and callbacks. The code usage is very similar, with react-cool-inview using a slightly different destructuring pattern. While react-intersection-observer has a larger user base and community support, react-cool-inview offers some advantages in terms of API flexibility and bundle size.

React components for efficiently rendering large lists and tabular data

Pros of react-window

  • Optimized for rendering large lists and tabular data efficiently
  • Supports both fixed-size and variable-size items
  • Provides smooth scrolling performance for large datasets

Cons of react-window

  • More complex setup and configuration compared to react-intersection-observer
  • Limited flexibility for dynamic content or irregular layouts
  • May require additional work to implement features like infinite scrolling

Code Comparison

react-window:

import { FixedSizeList } from 'react-window';

const Row = ({ index, style }) => (
  <div style={style}>Row {index}</div>
);

const Example = () => (
  <FixedSizeList
    height={150}
    itemCount={1000}
    itemSize={35}
    width={300}
  >
    {Row}
  </FixedSizeList>
);

react-intersection-observer:

import { useInView } from 'react-intersection-observer';

const Example = () => {
  const [ref, inView] = useInView({
    threshold: 0,
  });

  return (
    <div ref={ref}>
      {inView ? 'Element is visible' : 'Element is not visible'}
    </div>
  );
};

While react-window focuses on efficient rendering of large lists, react-intersection-observer provides a simpler API for detecting element visibility. The choice between the two depends on the specific use case and performance requirements of your application.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

React Intersection Observer

Build Status Codecov NPM version Dowloads per week


Bring ReactIntersectionObserver over today, your React children will love it!

React Intersection Observer is a React component, acting as a wrapper for the IntersectionObserver API. It is fully declarative and takes care of all the imperative parts for you.

React Intersection Observer is good at:

  • reusing instances: comparing the passed options
  • performance: chooses smartly when to re-render and when to re-observe
  • being unopinionated: how to handle visibility changes is left entirely up to the developer
  • being intuitive: looks like the Native API

Table of Contents

Getting started

npm install --save @researchgate/react-intersection-observer

:warning: Please make sure you have the minimum node version installed (as defined in the package.json)

Otherwise you run into this build error:

The engine "node" is incompatible with this module. Expected version ">=10.18.1". Got "10.15.3"

Usage

import React from 'react';
import 'intersection-observer'; // optional polyfill
import Observer from '@researchgate/react-intersection-observer';

class ExampleComponent extends React.Component {
  handleIntersection(event) {
    console.log(event.isIntersecting);
  }

  render() {
    const options = {
      onChange: this.handleIntersection,
      root: '#scrolling-container',
      rootMargin: '0% 0% -25%',
    };

    return (
      <div id="scrolling-container" style={{ overflow: 'scroll', height: 100 }}>
        <Observer {...options}>
          <div>I am the target element</div>
        </Observer>
      </div>
    );
  }
}

Optionally add the polyfill and make sure it's required on your dependendencies for unsupporting browsers:

npm install --save intersection-observer

What does IntersectionObserver do?

IntersectionObservers calculate how much of a target element overlaps (or "intersects with") the visible portion of a page, also known as the browser's "viewport":

Dan Callahan · Creative Commons License

Graphic example

Why use this component?

The motivation is to provide the easiest possible solution for observing elements that enter the viewport on your React codebase. It's fully declarative and all complexity is abstracted away, focusing on reusability, and low memory consumption.

No bookkeeping

It's built with compatibility in mind, adhering 100% to the native API implementation and DSL, but takes care of all the bookkeeping work for you.

Instances and nodes are managed internally so that any changes to the passed options or tree root reconciliation cleans up and re-observes nodes on-demand to avoid any unexpected memory leaks.

No extra markup

ReactIntersectionObserver does not create any extra DOM elements, it attaches to the only child you'll provide to it. This is done using findDOMNode to retrieve the first DOM node found. If your child already has an existing ref, either a callback or object (from createRef), these will be handled normally in either case.

Easy to adopt

When using ReactIntersectionObserver the only required prop is the onChange function. Any changes to the visibility of the element will invoke this callback, just like in the native API - you’ll receive one IntersectionObserverEntry argument per change. This gives you an ideal and flexible base to build upon.

Some of the things you may want to use ReactIntersectionObserver for:

Documentation

Demos

Find multiple examples and usage guidelines under: https://researchgate.github.io/react-intersection-observer/

demo

Recipes

Recipes are useful code snippets solutions to common problems, for example, how to use ReactIntersectionObserver within a Higher Order Component.
Here's how to create an element monitoring component:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Observer from '@researchgate/react-intersection-observer';

export default class ViewableMonitor extends Component {
  static propTypes = {
    tag: PropTypes.node,
    children: PropTypes.func.isRequired,
  };

  static defaultProps = {
    tag: 'div',
  };

  state = {
    isIntersecting: false,
  };

  handleChange = ({ isIntersecting }) => {
    this.setState({ isIntersecting });
  };

  render() {
    const { tag: Tag, children, ...rest } = this.props;

    return (
      <Observer {...rest} onChange={this.handleChange}>
        <Tag>{children(this.state.isIntersecting)}</Tag>
      </Observer>
    );
  }
}
import React from 'react';
import ViewableMonitor from './ViewableMonitor';

export default () => (
  <ViewableMonitor>
    {(isViewable) => (isViewable ? 'I am viewable' : 'I am still hiding')}
  </ViewableMonitor>
);

Discover more recipes in our examples section.

Missing DOM nodes when observing

In cases where there isn't a DOM node available to observe when rendering, you'll be seeing an error logged in the console:

ReactIntersectionObserver: Can't find DOM node in the provided children. Make sure to render at least one DOM node in the tree.

This somewhat helpful and descriptive message is supposed to help you identify potential problems implementing observers early on. If you miss the exception for some reason and ends up in production (prone to happen with dynamic children), the entire tree will unmount so be sensible about placing your error boundaries.

Ultimately the way to avoid this is to either make sure you are rendering a DOM node inside your <Observer>, or to disable the observer until there's one <Observer disabled>.

Options

root: HTMLElement|string | default window object

The element or selector string that is used as the viewport for checking visibility of the target.

rootMargin: string | default 0px 0px 0px 0px

Margin around the root. Specify using units px or % (top, right, bottom left). Can contain negative values.

threshold: number|Array<number> | default: 0

Indicates at what percentage of the target's visibility the observer's callback should be executed. If you only want to detect when visibility passes the 50% mark, you can use a value of 0.5. If you want the callback run every time visibility passes another 25%, you would specify the array [0, 0.25, 0.5, 0.75, 1].

disabled: boolean | default: false

Controls whether the element should stop being observed by its IntersectionObserver instance. Useful for temporarily disabling the observing mechanism and restoring it later.

onChange (required): (entry: IntersectionObserverEntry, unobserve: () => void) => void

Function that will be invoked whenever an observer's callback contains this target in its changes.

children: React.Element<*>|null

Single React component or element that is used as the target (observable). As of v1.0.0, children can be null. Null children won't be observed.

Notes

  • According to the spec, an initial event is being fired when starting to observe a non-intersecting element as well.
  • Changes happen asynchronously, similar to the way requestIdleCallback works.
  • Although you can consider callbacks immediate - always below 1 second - you can also get an immediate response on an element's visibility with observer.takeRecords().
  • The primitives Map an Set are required. You may need to include a polyfill for browsers lacking ES2015 support. If you're using babel, include "babel-polyfill" somewhere to your codebase.

Polyfill

When needing the full spec's support, we highly recommend using the IntersectionObserver polyfill.

Caveats

Ealier Spec

Earlier preview versions of Edge and prior to version 58 of Chrome, the support for isIntersecting was lacking. This property was added to the spec later and both teams where unable to implement it earlier.

Performance issues

As the above-mentioned polyfill doesn't perform callback invocation asynchronously, you might want to decorate your onChange callback with a requestIdleCallback or setTimeout call to avoid a potential performance degradation:

onChange = (entry) => requestIdleCallback(() => this.handleChange(entry));

IntersectionObserver's Browser Support

Out of the box

Chrome 51 [1]
Firefox (Gecko) 55 [2]
MS Edge 15
Internet Explorer Not supported
Opera [1] 38
Safari 12.1
Chrome for Android 59
Android Browser 56
Opera Mobile 37
  • [1]reportedly available, it didn't trigger the events on initial load and lacks isIntersecting until later versions.
  • [2] This feature was implemented in Gecko 53.0 (Firefox 53.0 / Thunderbird 53.0 / SeaMonkey 2.50) behind the preference dom.IntersectionObserver.enabled.

Using polyfill

Safari 6+
Internet Explorer 7+
Android 4.4+

Contributing

We'd love your help on creating React Intersection Observer!

Before you do, please read our Code of Conduct so you know what we expect when you contribute to our projects.

Our Contributing Guide tells you about our development process and what we're looking for, gives you instructions on how to issue bugs and suggest features, and explains how you can build and test your changes.

Haven't contributed to an open source project before? No problem! Contributing Guide has you covered as well.

NPM DownloadsLast 30 Days