# useScrollLock

Stops the page from scrolling while `locked` is `true`, e.g. behind a modal.

Sets `overflow: hidden` on `<body>` and pads it by the scrollbar width so the layout does not shift. Locks are counted, so nested modals work: the page unlocks when the last one releases. Restores the original styles. Applied in a layout effect, so there is no frame where the page can scroll.

## Import

```ts
import { useScrollLock } from '@vincent.ri/react-tils'
// or only this hook
import { useScrollLock } from '@vincent.ri/react-tils/useScrollLock'
```

## Usage

```ts
function Modal({ open, children }: { open: boolean; children: React.ReactNode }) {
  useScrollLock(open)
  return open ? <div role="dialog" aria-modal="true">{children}</div> : null
}
```

## When to use it

A modal, drawer, or full-screen menu is open.

## When not to

You use the native `<dialog>` with `showModal()`, where CSS `body:has(dialog[open]) { overflow: hidden }` is enough. To lock scrolling inside an element, use CSS `overscroll-behavior: contain`.

## API

```ts
function useScrollLock(locked?: boolean): void
```

| Parameter | Description |
| --- | --- |
| `locked` | Lock while `true`. Default `true`. |

## Browser support

Works in all modern browsers.

## Coming from another library?

Other libraries call this `useLockBodyScroll`.

---

270 B minified and brotlied
Source: https://github.com/vincentri/react-tils/blob/main/src/useScrollLock.ts
Docs page: https://vincentri.github.io/react-tils/hooks/useScrollLock/
Previous: [useServiceWorkerUpdate](https://vincentri.github.io/react-tils/hooks/useServiceWorkerUpdate.md)
Next: [useBeforeUnload](https://vincentri.github.io/react-tils/hooks/useBeforeUnload.md)
