Check if an Element is in the Viewport in React.js

avatar

Borislav Hadzhiev

Last updated: Apr 24, 2022

banner

Check out my new book

Check if an Element is in the Viewport in React.js #

To check if an element is in the viewport in React.js:

  1. Set the ref prop on the element.
  2. Use the IntersectionObserver API to track if the element is intersecting.
App.js
import {useEffect, useRef, useState, useMemo} from 'react'; export default function App() { const ref1 = useRef(null); const ref2 = useRef(null); const isInViewport1 = useIsInViewport(ref1); console.log('isInViewport1: ', isInViewport1); const isInViewport2 = useIsInViewport(ref2); console.log('isInViewport2: ', isInViewport2); return ( <div> <div ref={ref1}>Top div {isInViewport1 && '| in viewport ✅'}</div> <div style={{height: '155rem'}} /> <div ref={ref2}>Bottom div {isInViewport2 && '| in viewport ✅'}</div> </div> ); } function useIsInViewport(ref) { const [isIntersecting, setIsIntersecting] = useState(false); const observer = useMemo( () => new IntersectionObserver(([entry]) => setIsIntersecting(entry.isIntersecting), ), [], ); useEffect(() => { observer.observe(ref.current); return () => { observer.disconnect(); }; }, [ref, observer]); return isIntersecting; }

The example shows how to check if an element is in the viewport.

The IntersectionObserver API enables us to check if a given element is intersecting the document.

The useIsInViewport hook takes a ref object that points to the element we want to track.

The IntersectionObserver constructor takes a function that gets called with an array of entries.

Entries is an array of all of the obeserver's targeted elements which have become either more or less visible than one of the intersection observer ratios.

Each entry describes how much of a given element is intersecting with the root element (the document).

We destructured the entry, because our IntersectionObserver only tracks a single element (the element on which we set the ref).

We called the observe() method passing it the element we want to track - observer.observe(ref.current).

Every time the element enters the viewport or exists the viewport, the function we passed to the IntersectionObserver() constructor gets called and we update the state.

App.js
// 👇️ gets called every time element enters or leaves viewport new IntersectionObserver(([entry]) => setIsIntersecting(entry.isIntersecting), )

If the element on which we set the ref object is in the viewport, the useIsInViewport hook will return true.

If the element isn't in the viewport, the hook returns false.

Note that on the initial render, the useIsInViewport hook will return false because that's the initial value we passed to useState - const [isIntersecting, setIsIntersecting] = useState(false);.

If you want to track changes to the return value of the hook, use the useEffect hook and add the value to the hook's dependencies.

App.js
const isInViewport1 = useIsInViewport(ref1); console.log('isInViewport1: ', isInViewport1); useEffect(() => { // 👇️ listen for changes console.log(isInViewport1); }, [isInViewport1]);
I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.