Tutorial

How To Detect When a Component Enters the Viewport with React Visibility Sensor

React

Introduction

Programatically detecting when a React component enters the viewport requires scrolling event listeners and calculating the sizes of your elements.

Using React Visibility Sensor provides you with a React component that accomplishes this for you.

In this tutorial, you will learn how to use React Visibility Sensor to detect when your React components have entered the viewport.

Prerequisites

To complete this tutorial, you’ll need:

This tutorial was verified with Node v15.3.0, npm v6.14.9, react v17.0.1, and react-visibibilty-sensor v5.1.1.

Step 1 — Setting Up the Project

Consider the scenario of a page with multiple images. When an image enters the viewport, you would like to apply a CSS transition so the images fade in. You will apply the React Visibility Sensor to each image to accomplish this.

Start with using create-react-app to generate a React App and then install dependecies:

  • npx create-react-app react-visibility-sensor-example

Change into the new project directory:

  • cd react-visibility-sensor-example

Install the react-visibility-sensor package:

  • npm install react-visibility-sensor@5.1.1

Now, you can run the React application:

  • npm start

Fix any errors or issues with your project. And visit localhost:3000 in a web browser.

Once you have a working React application, you can start building your custom component with viewport detection.

Step 2 — Applying React Visibility Sensor

Create a new VisibilitySensorImage.js file with your text editor:

src/VisibilitySensorImage.js
import React, { Component } from 'react';
import VisibilitySensor from 'react-visibility-sensor';

class VisibilitySensorImage extends Component {
  state = {
    visibility: false
  }

  render() {
    return (
      <VisibilitySensor
        onChange={(isVisible) => {
          this.setState({visibility: isVisible})
        }}
      >
        <img
          alt={this.props.alt}
          src={this.props.src}
          style={{
            display: 'block',
            maxWidth: '100%',
            width: '100%',
            height: 'auto',
            opacity: this.state.visibility ? 1 : 0.25,
            transition: 'opacity 500ms linear'
          }}
        />
      </VisibilitySensor>
    );
  }
}

export default VisibilitySensorImage;

This component uses the VisibilitySensor component made available by react-visibility-sensor. When a change event is detected, a check is performed to determine if the component is visible.

This code uses a ternary operator to determine whether to set the opacity to 0.25 or 1. If the image is not in the viewport, an opacity of 0.25 is applied. If the image is in the viewport, an opacity of 1 is applied.

Next, use the new component you created to observe it in action.

Open the App.js file and modify it to use VisibilitySensorImage:

src/App.js
import VisibilitySensorImage from './VisibilitySensorImage';

function App() {
  return (
    <div className="App">
      <h1>Astronomy</h1>
      {[
        'https://apod.nasa.gov/apod/image/2012/AntennaeGpotw1345a_1024.jpg',
        'https://apod.nasa.gov/apod/image/2012/Neyerm63_l1_1024.jpg',
        'https://apod.nasa.gov/apod/image/2012/2020Dec14TSE_Ribas_IMG_9291c1024.jpg',
        'https://apod.nasa.gov/apod/image/2012/ChristmasTree-ConeNebula-CumeadaObservatoryDSA-net1100.jpg',
        'https://apod.nasa.gov/apod/image/2012/EagleNebula_Paladini_960.jpg'
      ].map((imgpath) => <VisibilitySensorImage src={imgpath} alt="Astronomy Image"/>)}
    </div>
  );
}

export default App;

Now, when you run your React application, you should observe images appearing on the screen. As you scroll down the screen, the opacity of the images should change with a “fade-in” visual effect.

However, in this example, the effect is only visible on narrow screens. If the images are larger than the viewport, they may not be detected as isVisible. You can use customize the props available to React Visibility Sensor to suit your needs.

Step 3 — Customizing React Visibility Sensor

The documentation for React Visibility Sensor contains many props for customization.

The partialVisibility prop will be useful to address the issue with components larger than the viewport.

Revisit the VisibilitySensorImage and add partialVisibility:

src/VisibilitySensorImage.js
import React, { Component } from 'react';
import VisibilitySensor from 'react-visibility-sensor';

class VisibilitySensorImage extends Component {
  state = {
    visibility: false
  }

  render() {
    return (
      <VisibilitySensor
        partialVisibility
        onChange={(isVisible) => {
          this.setState({visibility: isVisible})
        }}
      >
        <img
          alt={this.props.alt}
          src={this.props.src}
          style={{
            display: 'block',
            maxWidth: '100%',
            width: '100%',
            height: 'auto',
            opacity: this.state.visibility ? 1 : 0.25,
            transition: 'opacity 500ms linear'
          }}
        />
      </VisibilitySensor>
    );
  }
}

export default VisibilitySensorImage;

Now, if you scroll the page the opacity changes when for images when they are partially in the viewport.

In addition to partialVisibility there are many customization props:

  • Throttling the scroll listener.
  • Specifying the minimum number of pixels to appear in the viewport (default: when partialVisibility is true elements are considered visible when only 1 pixel appears).
  • Listen when the browser window is resized.
  • Or deactivating the scroll listener altogether if you do not need to listen for the event any longer.

Conclusion

In this tutorial, you learned how to use React Visibility Sensor to detect when your React components have entered the viewport.

The example in this tutorial involved images fading in and out as they enter and leave the viewport. But there is also the potential for other usages:

  • Lazy-loading images when they are visible.
  • Display a “Thanks for Visiting!” message when users have scrolled to the footer of your website.
  • Logging custom events to Google Analytics.
  • Expanding a comment widget when users scroll to the end of a blog post.

If you’d like to learn more about React, take a look at our How To Code in React.js series, or check out our React topic page for exercises and programming projects.

Creative Commons License