Performing any action based on the visibility of a particular element can prove to be a hassle.
In this article, I will show you how to use the Intersection Observer API in React in order to perform certain actions when a particular element is in/out of the viewport.
Intersection Observer can be helpful in the following cases:
- Lazy-loading of images or other content as a page is scrolled.
- Infinite Scrolling: Render more and more content as the user scrolls down
- Reporting of visibility of advertisements in order to calculate ad revenues.
- Performing animation processes based on whether or not the user will see the result.
Initializing an Intersection Observer is really easy.
const observer = new IntersectionObserver(callback, options); observer.observe(elementToBeObserved);
It requires two arguments:
- callback: The callback function to be invoked when the element is visible.
- options: Determines the properties of the viewport. Takes an object of the following format:
const options = { root: null, threshold: 0, rootMargin: "0px", };
- root: The element to be used as the viewport for checking the visibility of the target. Must be the ancestor of the target. Takes
null
as default value (i.e. browser’s viewport) - rootMargin: Margin around the root. We can specify values in the format “
5px 10px 15px 20px"
(top, right, bottom, left). The values can be either in pixels or percentages. This set of values serves to grow or shrink the size of the root element. Defaults to all zeros. - threshold: Takes either a single number or an array of numbers indicating the percentage of the target’s visibility on which the callback should be executed, ranges from 0 to 1.0, where 1.0 means every pixel is visible in the viewport. Takes
0
as default value (i.e. the callback is executed as soon as even one pixel is visible).
Let’s implement it in React.
Paste the following code snippet in App.js
import React, { useEffect, useRef, useState } from "react"; import "./styles.css"; export default function App() { const eleRef = useRef(); const [isIntersecting, setIsIntersecting] = useState(false); useEffect(() => { const observer = new IntersectionObserver( (entries, observer) => { const [entry] = entries; setIsIntersecting(entry.isIntersecting); }, { root: null, rootMargin: "0px", threshold: 0.75 // at least 75% of the sction should be visible } ); if (eleRef.current) observer.observe(eleRef.current); return () => { if (eleRef.current) observer.unobserve(eleRef.current); }; }, [eleRef]); return ( <div className="App"> <h1>{`The section is ${ isIntersecting ? "visible" : "not visible. Scroll to see" }.`}</h1> <h2></h2> <section ref={eleRef} className="scroll-element"> I am in the viweport. </section> </div> ); }
Paste the CSS stylings in styles.css
body { box-sizing: border-box; margin: 0; padding: 0; height: 100vh; } .App { font-family: sans-serif; text-align: center; height: 100vh; } h1 { position: fixed; } h2 { height: 100vh; } .scroll-element { height: 100vh; background-color: blueviolet; overflow: scroll; }On running the code, the result will be as shown:
https://vectoscalar.com/media/b96017ba781190df4434515add61f731
And that’s it. Although it is a basic implementation of the Intersection Observer API, many more creative things can be done with it. Try it and do let me know if any improvements can be made.
Thank you!