Article thumbnail

🔰 Hiding window and HTML element scroll with the useScrollHide hook

5m
frontend
ui
hooks

Intro

Discover techniques to programmatically show/hide scroll, default, and custom. Leverage the useScrollHide hook for enhanced control in Modals and components.

The use cases for the useScrollHide hook

Imagine you've Modal component and during display, you have double scroll. First is window scroll and the second scroll is inside Modal. It may cause weird UX and frustrating to use UI. The best approach to improve that is just disabling the scroll on window when Modal is displayed.

To understand the use case check the following GIF:

Loading

How our hook works in the context of Modal component

This hook may be used to hide/show scroll programmatically for window or other HTML elements. It may be useful when you create any component that appears on the screen and contains a scroll - menu, select, dialog, alert, ...etc.

How to use the useScrollHide hook?

We'll use our hook in 2 scenarios: with window and with any other HTML element.

Loading

If we want to use the scroll hide mechanism and apply it to HTML element, we need to pass the type of this element to our hook.

In addition, we have 2 methods to programmatically maintain the scroll.

Implementation process

Check the following GIF to understand how it was implemented step by step:

Loading

Implementation process

Let's start the explanation with boilerplate for our hook.

Loading

Now, we need a mechanism that determines what we should track (window or HTML element). We should pick the HTML element if the value of ref is assigned - different than null. Otherwise, it will be a window.

Loading

We want to hide the scroll just after the component is mounted. So, we need the effect. It will work like this:

  • if the component is mounted - we'll call the 'hide' function to hide scroll,
  • if the component is unmounted - we'll call the 'show' function to restore scroll.

Loading

We need to store initial styles for our target element in which we want to hide/show scroll. For that, we'll also use ref object. It's because it will store these values per hook usage and will not cause additional rerenders like useState hook.

Loading

Why the overflow value is auto by default? If the target element (window or HTML element) will not have a overflow, we want to set this value to auto - to make the scroll working as before.

Last but not least, we need to implement show and hide functions.

Loading

In each, at the beginning we get an element - the window or HTML element. Next, we are assigning styles to hide and show scroll.

Now, it will work, but we're using useEffect to perform some DOM operations - reading values and changing styles.

We've used useEffect, but we should use useLayoutEffect which is designed for that case - it's executed after browser repaints our view - so we will be sure that our styles data is up to date.

Loading

Last thing... Still, we need to take into consideration server-side rendering. Right now we'll have logged bad looking error/warning on server side (Next or Gatsby). To fix that we need to use abstraction for useLayoutEffect that blocks executing it on server-side.

Loading

I'm using useIsomorphicLayoutEffect in almost all hooks that I implemented if I want to use useLayoutEffect. If you want to understand what this hook does, check the following 🔰 Removing server warnings for useLayoutEffect with a custom hook article.

The complete implementation with tests and separated type definitions

Check the final code in the following Dream stack for React developer repository. Below you've snippets to explore and use in your projects.

Loading

Loading

Loading

Conclusions

Now you know how to hide scroll for dedicated UI components with a reusable hook. We've learned that server side code may prompt an error/warning if we use useLayoutEffect on the server.

I create content regularly!

I hope you found my post interesting. If so, maybe you'll take a peek at my LinkedIn, where I publish posts daily.

Comments

Add your honest opinion about this article and help us improve the content.

created: 20-03-2023
updated: 20-03-2023