useScrollLock
Prevent body or element scrolling with reference counting. Multiple locks on the same element stack.
useScrollLock prevents an element from scrolling while it is enabled, then restores the previous overflow when released. Locks are reference-counted per element, so two overlays can lock document.body independently and scrolling is only restored once both release. It is standalone (no provider) and ships as a copy-paste utility hook.
When to use it
- Freeze background scroll behind a modal, drawer, sheet, or full-screen overlay.
- Lock a specific scroll container (pass
target) rather than the whole page.
Pair it with useFocusTrap to hold focus inside a modal while its background is locked.
Limitations
useScrollLock toggles overflow: hidden on the target element with refcounted restore. It also compensates for scrollbar width with padding-right and marks the locked element with data-scroll-locked. It does not implement the full react-remove-scroll / Radix useScrollLock parity surface:
-
Defaults to the host
document.body. In multi-window or iframe setups, capture the trigger's owner document after mount and pass a ref to that document's body:tsxMount order matters: register the effect before calling
useScrollLockso the target ref is populated before the lock effect runs. -
No iOS Safari rubber-band guard. Setting
overflow: hiddenon body does not stop iOS touch scrolling. The page can still pan-scroll on iOS while the lock is active.
iOS rubber-band compensation is not part of the current surface; use a dedicated touch-scroll guard when that behavior matters.
Installation
dgadd is not public on npm yet. Until the first release, pack @diffgazer/add from the repository and install that tarball into this app, which is what puts dgadd on pnpm exec.
The hosted registry is not public yet because r.b4r7.dev does not resolve. Use this source checkout or a local registry preview until the endpoint returns 200.
Diffgazer packages are not yet published to npm. Until the first release, pack @diffgazer/ui and @diffgazer/keys from the repository and install those tarballs.
@diffgazer/keys requires no CSS or Tailwind setup.
Parameters
Returns
Examples
Lock body scroll in a modal
Lock a specific scroll container
Notes
Reference counting
Multiple useScrollLock calls on the same element increment a shared counter. Scrolling is only restored when all locks are released, preventing double-unlock bugs.
Standalone
useScrollLock does not require KeyboardProvider. It works independently as a copy-paste utility hook.
Edge cases
- Toggling
enabled. Flippingenabledtofalsereleases this hook's lock immediately; the element stays locked while any other lock remains.
Related
useFocusTrap— trap focus inside the modal whose background you lock.- Focus and scroll guide — composing scroll lock with focus management.
Source
Highlighted source loads after this disclosure opens. Browse the source repository.