npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-scroll-blocker

v1.0.6

Published

A modern React 18 compatible scroll lock component for preventing body scroll

Readme

React Scroll Blocker

🔒 A modern, React 18 compatible library for preventing body scroll when components are mounted.

npm version License: MIT

🌐 Try the Interactive Demo →

Why React Scroll Blocker?

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.

Features

  • 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

Installation

npm install react-scroll-blocker
# or
yarn add react-scroll-blocker
# or
pnpm add react-scroll-blocker

Quick Start

import React, { useState } from 'react'
import ScrollBlocker from 'react-scroll-blocker'

function MyModal() {
	const [isOpen, setIsOpen] = useState(false)

	return (
		<div>
			<button onClick={() => setIsOpen(true)}>Open Modal</button>

			{isOpen && (
				<>
					{/* This will prevent body scroll while the modal is open */}
					<ScrollBlocker />

					<div
						className='modal-overlay'
						onClick={() => setIsOpen(false)}>
						<div
							className='modal-content'
							onClick={(e) => e.stopPropagation()}>
							<h2>Modal Title</h2>
							<p>Modal content here...</p>
							<button onClick={() => setIsOpen(false)}>Close</button>
						</div>
					</div>
				</>
			)}
		</div>
	)
}

API Reference

ScrollBlocker Component

The main component that prevents body scroll when mounted.

import ScrollBlocker from 'react-scroll-blocker'
;<ScrollBlocker
	isActive={true} // Optional: whether the blocker is active (default: true)
	accountForScrollbars={true} // Optional: prevent layout shift (default: true)
>
	{/* Optional: scrollable content for mobile */}
</ScrollBlocker>

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 |

useScrollBlocker Hook

A React hook that provides programmatic control over scroll blocking.

import { useScrollBlocker } from 'react-scroll-blocker'

function MyComponent() {
	const { blockScroll, unblockScroll, isBlocked } = useScrollBlocker()

	return (
		<div>
			<button onClick={blockScroll}>Block Scroll</button>
			<button onClick={unblockScroll}>Unblock Scroll</button>
			<p>Scroll is {isBlocked ? 'blocked' : 'unblocked'}</p>
		</div>
	)
}

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 |

TouchScrollable Component

A component that allows its children to remain scrollable even when ScrollBlocker is active. This is particularly useful for mobile devices.

import { ScrollBlocker, TouchScrollable } from 'react-scroll-blocker'

function ScrollableModal() {
	return (
		<>
			<ScrollBlocker />
			<TouchScrollable>
				<div className='scrollable-content'>
					{/* This content will be scrollable on mobile */}
				</div>
			</TouchScrollable>
		</>
	)
}

Alternative: Automatic TouchScrollable

When you pass children to ScrollBlocker, they are automatically wrapped in TouchScrollable:

<ScrollBlocker>
	<div className='scrollable-content'>
		{/* Automatically scrollable on mobile */}
	</div>
</ScrollBlocker>

Usage Examples

Basic Modal

import React, { useState } from 'react'
import ScrollBlocker from 'react-scroll-blocker'

function Modal() {
	const [isOpen, setIsOpen] = useState(false)

	return (
		<div>
			<button onClick={() => setIsOpen(true)}>Open Modal</button>

			{isOpen && (
				<>
					<ScrollBlocker />
					<div
						style={
							{
								/* modal styles */
							}
						}>
						<h2>Modal Content</h2>
						<button onClick={() => setIsOpen(false)}>Close</button>
					</div>
				</>
			)}
		</div>
	)
}

Conditional Scroll Lock

import ScrollBlocker from 'react-scroll-blocker'

function ConditionalLock({ shouldLock }) {
	return (
		<div>
			<ScrollBlocker isActive={shouldLock} />
			<p>Scroll is {shouldLock ? 'locked' : 'unlocked'}</p>
		</div>
	)
}

Hook-based Approach

import { useScrollBlocker } from 'react-scroll-blocker'

function HookExample() {
	const [isModalOpen, setIsModalOpen] = useState(false)
	const { lockScroll, unlockScroll } = useScrollBlocker(isModalOpen)

	return (
		<div>
			<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
			{/* Modal JSX */}
		</div>
	)
}

Scrollable Modal Content

import ScrollBlocker from 'react-scroll-blocker'

function ScrollableModal() {
	return (
		<ScrollBlocker>
			<div
				style={{
					position: 'fixed',
					top: '10%',
					bottom: '10%',
					left: '10%',
					right: '10%',
					overflow: 'auto', // This content will be scrollable
				}}>
				<div style={{ height: '200vh' }}>Long scrollable content...</div>
			</div>
		</ScrollBlocker>
	)
}

Multiple Nested Locks

import ScrollBlocker from 'react-scroll-blocker'

function NestedModals() {
	const [modal1Open, setModal1Open] = useState(false)
	const [modal2Open, setModal2Open] = useState(false)

	return (
		<div>
			{modal1Open && <ScrollBlocker />}
			{modal2Open && <ScrollBlocker />}

			{/* Both modals can be open simultaneously */}
			{/* Scroll is locked while any modal is open */}
			{/* Scroll is restored only when both are closed */}
		</div>
	)
}

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:

// 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

Breaking Changes from react-scrolllock

  • 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!