Urgent.News

One page, thousands of outlets. See who else covered it.

Editions

Tech

React useScrollLock Hook: Lock Body Scroll for Modals (2026)

Your modal is open, centered, perfect. Then someone flicks the overlay and the page behind it scrolls away underneath. Everyone's first fix is the same three lines: useEffect (() => { document . body . style . overflow = open ? " hidden " : "" ; }, [ open ]); It works on your laptop. Then the bug reports arrive: On iPhone the page still moves. iOS Safari rubber-band scrolls the document by touch…

The React useScrollLock hook is a solution to prevent page scrolling when a modal is open. The issue arises when a modal is opened, centered, and appears perfect. However, someone flicks the overlay, and the page behind it scrolls away, causing frustration. The common three-line fix is to use useEffect to set the overflow property of the document.body to hidden or not, depending on the open state of the modal.

This fix works on laptops but has bugs on iPhones and with iOS Safari. The useScrollLock hook from @reactuses/core addresses these issues by restoring the exact inline overflow it replaced, adding a touchmove guard on iOS, and exposing the lock as React state that can be rendered off. It works on any element, not just the body. To use it, install @reactuses/core and import the useScrollLock hook.

The hook returns an array with two elements: locked, which is real state, and setLocked, which is identity-stable. The signature includes a target, which is the element whose scrolling you're locking, and an optional initialState, which sets the initial locked state. The hook handles the overflow property, touchmove events on iOS, and returns the locked and setLocked values. There are six potential gotchas to be aware of when using the useScrollLock hook in real apps.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

More from Wednesday 19 August →