Loading...
Please waitLoading...
Please waitpnpm dlx uselab@latest add use-scroll-blocker
import * as React from "react"
import { useScrollBlocker } from "@/hooks/use-scroll-blocker"
function Modal() {
const [isOpen, setIsOpen] = React.useState(false)
const { block, unblock } = useScrollBlocker()
const handleOpen = () => {
setIsOpen(true)
block()
}
const handleClose = () => {
setIsOpen(false)
unblock()
}
return (
<>
<button onClick={handleOpen}>Open Modal</button>
{isOpen && (
<div className="modal">
<button onClick={handleClose}>Close</button>
</div>
)}
</>
)
}The hook provides manual control over scroll blocking, allowing you to block and unblock scrolling at the right moments in your component lifecycle.
useScrollBlocker()Returns an object with two methods:
| Name | Type | Description |
|---|---|---|
block | () => void | Block background scrolling and preserve position |
unblock | () => void | Unblock background scrolling and restore position |
import { useScrollBlocker } from "@/hooks/use-scroll-blocker"
function MyModal() {
const [open, setOpen] = React.useState(false)
const { block, unblock } = useScrollBlocker()
React.useEffect(() => {
if (open) {
block()
} else {
unblock()
}
}, [open, block, unblock])
return (
<>
<button onClick={() => setOpen(true)}>Open</button>
{open && (
<div className="modal">
<button onClick={() => setOpen(false)}>Close</button>
</div>
)}
</>
)
}import { useScrollBlocker } from "@/hooks/use-scroll-blocker"
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
function MyDialog() {
const [open, setOpen] = React.useState(false)
const { block, unblock } = useScrollBlocker()
React.useEffect(() => {
if (open) {
block()
} else {
unblock()
}
}, [open, block, unblock])
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger>Open Dialog</DialogTrigger>
<DialogContent>
<p>Dialog content</p>
</DialogContent>
</Dialog>
)
}function App() {
const [modal1Open, setModal1Open] = React.useState(false)
const [modal2Open, setModal2Open] = React.useState(false)
const { block, unblock } = useScrollBlocker()
React.useEffect(() => {
if (modal1Open || modal2Open) {
block()
} else {
unblock()
}
}, [modal1Open, modal2Open, block, unblock])
return (
<>
<button onClick={() => setModal1Open(true)}>Open Modal 1</button>
<button onClick={() => setModal2Open(true)}>Open Modal 2</button>
{/* modals */}
</>
)
}block() are handled correctly — scroll only unblocks when all instances call unblock()Click the button above to open a modal. Notice how the background page cannot be scrolled while the modal is open.
block() when opening a modal or popupunblock() when closing itScroll this page up and down, then open the modal. Notice how the background stays fixed while the modal is open. This prevents users from accidentally scrolling the content behind modals.