useScrollLock
Prevent body scroll when modals or overlays are open. Prevents layout shift by reserving scrollbar space.
Live Demo
💡 Try this: Scroll down this page, then open the modal. Notice how the body scroll is locked while the modal is open!
Scroll down to test the scroll lock feature
This content makes the page scrollable. Open the modal to see scroll locking in action.
Code Examples
Basic Modal with Scroll Lock
import { useScrollLock } from "@uiblock/hooks";
import { useState } from "react";
function Modal({ isOpen, onClose, children }) {
useScrollLock({ enabled: isOpen });
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
{children}
<button onClick={onClose}>Close</button>
</div>
</div>
);
}With Options
import { useScrollLock } from "@uiblock/hooks";
function Drawer({ isOpen }) {
useScrollLock({
enabled: isOpen,
reserveScrollBarGap: true, // Prevent layout shift
allowTouchMove: false // Prevent touch scrolling
});
return isOpen ? <div>Drawer content</div> : null;
}How It Works
Here's the implementation:
import { useEffect } from 'react'
export function useScrollLock(options = {}) {
const {
enabled = true,
reserveScrollBarGap = true,
allowTouchMove = false
} = options
useEffect(() => {
if (!enabled) return
const originalStyle = {
overflow: document.body.style.overflow,
paddingRight: document.body.style.paddingRight
}
// Calculate scrollbar width
const scrollBarWidth = window.innerWidth - document.documentElement.clientWidth
// Lock scroll
document.body.style.overflow = 'hidden'
// Reserve scrollbar space to prevent layout shift
if (reserveScrollBarGap && scrollBarWidth > 0) {
document.body.style.paddingRight = `${scrollBarWidth}px`
}
// Prevent touch move if not allowed
const preventTouchMove = (e) => {
if (!allowTouchMove) {
e.preventDefault()
}
}
if (!allowTouchMove) {
document.addEventListener('touchmove', preventTouchMove, {
passive: false
})
}
// Cleanup
return () => {
document.body.style.overflow = originalStyle.overflow
document.body.style.paddingRight = originalStyle.paddingRight
if (!allowTouchMove) {
document.removeEventListener('touchmove', preventTouchMove)
}
}
}, [enabled, reserveScrollBarGap, allowTouchMove])
}Key Features:
- Prevents body scroll when enabled
- Reserves scrollbar space to prevent layout shift
- Optionally prevents touch scrolling
- Automatic cleanup on unmount
API Reference
Options
enabled?: booleanWhether to lock the scroll (default: true)
reserveScrollBarGap?: booleanReserve space for scrollbar to prevent layout shift (default: true)
allowTouchMove?: booleanAllow touch move events (default: false)
💡 Use Cases
- Modal dialogs
- Side drawers
- Full-screen overlays
- Mobile menus
- Lightboxes