logo
Go Back

Add basic scroll-to-reveal transition in ReactJs

Title 1
Title 2
Title 3
Title 4

Adding a transition to the website, will make your site more appealing and make users want to spend more time playing around with it. Transitions in a website can be performed in various ways:

  • Mouse click
  • Mouse hover
  • Mouse move
  • Scrolling

Here I'd love to share a reusable code snippet to have the basic scroll-to-reveal in ReactJs.
In the past, we will need to get the current body dom's scrollHeight and each component's current height and calculate if the component is revealing. Now we have a handy IntersectionObserver API to take care of all the viewport calculation work.

Let's dive into the code:

useScrollToReveal.ts

import { useEffect, useRef, useState } from 'react';

function useScrollToReveal(): {
  domRef: React.MutableRefObject<any>;
  fadeInStyle: React.CSSProperties;
} {
  const domRef = useRef<any>(null);

  const [isVisible, setVisible] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (!domRef || !domRef.current) return;

        // In your case there's only one element to observe:
        if (entries[0].isIntersecting) {
          setTimeout(() => setVisible(true), 450);
          // No need to keep observing:
          observer.unobserve(domRef.current);
        }
      },
      { rootMargin: '48px' }
    );

    if (domRef && domRef.current) {
      observer.observe(domRef && domRef.current);
    }

    return () => {
      if (domRef && domRef.current) {
        observer.unobserve(domRef.current);
      }
    };
  }, []);

  return {
    domRef,
    fadeInStyle: { transition: 'all .8s ease-in', opacity: isVisible ? 1 : 0 },
  };
}

export default useScrollToReveal;

Example.tsx

import useScrollToReveal from '@hooks/useScrollToReveal';

function RevealBlock({ title }) {
  const { domRef, fadeInStyle } = useScrollToReveal();

  return (
    <div
      {/* Assign the domRef from useScrollToReveal hook, allow the hook know which component to observe */}
      ref={domRef}
      style={{
        ...fadeInStyle,
        height: '300px',
        fontSize: '1.25rem',
        backgroundColor: '#FCD9B8',
        color: '#222',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        marginBottom: '72px',
      }}
    >
      {title}
    </div>
  );
}

function ScrollToRevealExample() {
  return (
    <>
      <RevealBlock title="Title 1" />
      <RevealBlock title="Title 2" />
      <RevealBlock title="Title 3" />
      <RevealBlock title="Title 4" />
    </>
  );
}

export default ScrollToRevealExample;

2024 ❤️ MH (Frank) Tsai