A modern React 18 compatible scroll lock component for preventing body scroll
npm install react-scroll-blockerš A modern, React 18 compatible library for preventing body scroll when components are mounted.


This library was created as a modern alternative to react-scrolllock, which is no longer maintained and doesn't support React 18. React Scroll Blocker provides the same functionality with modern React practices, TypeScript support, and React 18 compatibility.
- ā
React 18 Compatible - Full support for React 18 and its concurrent features
- ā
TypeScript Support - Written in TypeScript with full type definitions
- ā
Zero Dependencies - No external dependencies except React
- ā
Mobile Friendly - Handles iOS Safari scroll issues correctly
- ā
Layout Shift Prevention - Accounts for scrollbar width to prevent layout jumps
- ā
Multiple Instances - Support for nested/multiple scroll locks
- ā
Hook Support - Includes both component and hook APIs
- ā
Touch Scrollable Areas - Allow specific elements to remain scrollable
- ā
Server-Side Rendering - Works with SSR/Next.js
``bash`
npm install react-scroll-blockeror
yarn add react-scroll-blockeror
pnpm add react-scroll-blocker
`tsx
import React, { useState } from 'react'
import ScrollBlocker from 'react-scroll-blocker'
function MyModal() {
const [isOpen, setIsOpen] = useState(false)
return (
{isOpen && (
<>
{/ This will prevent body scroll while the modal is open /}
className='modal-overlay'
Modal content here...
API Reference
$3
The main component that prevents body scroll when mounted.
`tsx
import ScrollBlocker from 'react-scroll-blocker'
; isActive={true} // Optional: whether the blocker is active (default: true)
accountForScrollbars={true} // Optional: prevent layout shift (default: true)
>
{/ Optional: scrollable content for mobile /}
`#### Props
| Prop | Type | Default | Description |
| ---------------------- | ----------- | ----------- | ------------------------------------------------------------- |
|
isActive | boolean | true | Whether the scroll blocker is active |
| accountForScrollbars | boolean | true | Whether to add padding to compensate for removed scrollbar |
| children | ReactNode | undefined | Child elements that should remain scrollable on touch devices |$3
A React hook that provides programmatic control over scroll blocking.
`tsx
import { useScrollBlocker } from 'react-scroll-blocker'function MyComponent() {
const { blockScroll, unblockScroll, isBlocked } = useScrollBlocker()
return (
Scroll is {isBlocked ? 'blocked' : 'unblocked'}
)
}
`#### Parameters
| Parameter | Type | Default | Description |
| ---------------------- | --------- | ------- | -------------------------------------- |
|
isBlocked | boolean | false | Whether scroll should be blocked |
| accountForScrollbars | boolean | true | Whether to account for scrollbar width |#### Returns
| Property | Type | Description |
| --------------- | ------------ | ----------------------------------- |
|
blockScroll | () => void | Function to manually block scroll |
| unblockScroll | () => void | Function to manually unblock scroll |
| isBlocked | boolean | Current block state |$3
A component that allows its children to remain scrollable even when ScrollBlocker is active. This is particularly useful for mobile devices.
`tsx
import { ScrollBlocker, TouchScrollable } from 'react-scroll-blocker'function ScrollableModal() {
return (
<>
{/ This content will be scrollable on mobile /}
>
)
}
`#### Alternative: Automatic TouchScrollable
When you pass children to ScrollBlocker, they are automatically wrapped in TouchScrollable:
`tsx
{/ Automatically scrollable on mobile /}
`Usage Examples
$3
`tsx
import React, { useState } from 'react'
import ScrollBlocker from 'react-scroll-blocker'function Modal() {
const [isOpen, setIsOpen] = useState(false)
return (
{isOpen && (
<>
style={
{
/ modal styles /
}
}>
Modal Content
>
)}
$3
`tsx
import ScrollBlocker from 'react-scroll-blocker'function ConditionalLock({ shouldLock }) {
return (
Scroll is {shouldLock ? 'locked' : 'unlocked'}
)
}
`$3
`tsx
import { useScrollBlocker } from 'react-scroll-blocker'function HookExample() {
const [isModalOpen, setIsModalOpen] = useState(false)
const { lockScroll, unlockScroll } = useScrollBlocker(isModalOpen)
return (
{/ Modal JSX /}
)
}
`$3
`tsx
import ScrollBlocker from 'react-scroll-blocker'function ScrollableModal() {
return (
style={{
position: 'fixed',
top: '10%',
bottom: '10%',
left: '10%',
right: '10%',
overflow: 'auto', // This content will be scrollable
}}>
Long scrollable content...
$3
`tsx
import ScrollBlocker from 'react-scroll-blocker'function NestedModals() {
const [modal1Open, setModal1Open] = useState(false)
const [modal2Open, setModal2Open] = useState(false)
return (
{modal1Open && }
{modal2Open && } {/ Both modals can be open simultaneously /}
{/ Scroll is locked while any modal is open /}
{/ Scroll is restored only when both are closed /}
)
}
`Browser Support
- ā
Chrome (latest)
- ā
Firefox (latest)
- ā
Safari (latest)
- ā
Edge (latest)
- ā
iOS Safari
- ā
Chrome Mobile
- ā
Samsung Internet
Migration from react-scrolllock
React Scroll Blocker is designed as a drop-in replacement for react-scrolllock:
`tsx
// Before (react-scrolllock)
import ScrollLock, { TouchScrollable } from 'react-scrolllock'// After (react-scroll-blocker)
import ScrollBlocker, { TouchScrollable } from 'react-scroll-blocker'
// Note: Component name changed from ScrollLock to ScrollBlocker
`$3
- React 18 Required: This library requires React 18+
- TypeScript: Full TypeScript support (may require type updates)
- Modern Build: Uses modern build tools and ES modules
Contributing
We welcome contributions! Please see our Contributing Guide for details.
License
MIT Ā© lomelo-x
Acknowledgments
This library is inspired by and serves as a modern replacement for
react-scrolllock` by Joss Mackison. Thanks for the original implementation and inspiration!