DEV Community

Minh-Phuc Tran
Minh-Phuc Tran

Posted on • Originally published at phuctm97.com

Auto Shrink Header On Scroll in React

I've always liked this effect: keep the header of your website sticky then auto-shrink and blur when users scroll down.

Demo

Today, I finally got some free time to implement it for my website, so I'm writing this article hopefully to help you do the same for yours if you also like it 😉.

Motivations

There're 2 primary motivations that makes me love this effect:

  • You can put a couple of calls to action (CTAs), then as your users are reading content on your website, they keep seeing these CTAs, which can increase the odds that they'll click them. I like to keep links to my newsletter and Twitter here. (An extra tip that I like to do here is to make a little animation or transition that occasionally runs to remind the user's the CTAs)

  • I want to optimize for CTAs but I don't want users on my website to have bad experience, which is actually even more important. To avoid bad UX, the header shouldn't take too much space, especially when users are reading the main content.

How-to

Basic idea

The basic idea is to subscribe to onscroll event of the browser, then check if the user scrolls pass a certain offset and update CSS of the header component arcordingly.

Subscribe to onscroll using hook



const Header = () => {
  useEffect(() => {
    const handler = () => {
      // Check and update component here.
    };

    window.addEventListener("scroll", handler);
    return () => window.removeEventListener("scroll", handler);
  }, []);

  // return <Component ... />
};


Enter fullscreen mode Exit fullscreen mode

Use useEffect hook to subscribe to event onscroll when the component is mounted (notice the last parameter []), also remember to return an unsubscribe function when the component is unmounted to avoid memory leaks.

Check for scroll position



const Header = () => {
  const [isShrunk, setShrunk] = useState(false);

  useEffect(() => {
    const handler = () => {
      setShrunk((isShrunk) => {
        if (
          !isShrunk &&
          (document.body.scrollTop > 20 ||
            document.documentElement.scrollTop > 20)
        ) {
          return true;
        }

        if (
          isShrunk &&
          document.body.scrollTop < 4 &&
          document.documentElement.scrollTop < 4
        ) {
          return false;
        }

        return isShrunk;
      });
    };

    // Previous logic.
  }, []);

  // return <Component isShrunk={isShrunk} />
};


Enter fullscreen mode Exit fullscreen mode

Notice setShrunk is called with a function instead of just pure value, this pattern helps ensure we are checking against the lastest previous value. Also, there are a gap between offsets to shrink and to expand (20 and 4), this helps avoid flashing of changed styles.

That's it. I hope it helps. Check out the full source code to see more details.

Top comments (0)