lockScroll
elements man ui/behaviors/scroll-lockStops the page scrolling under a modal. Locks nest: the page unlocks when
the last lock is released, so a dialog opened from a dialog is safe. The
lock sets overflow: hidden on <html>, so it captures no events: every
scroller inside the modal keeps scrolling natively, pinch zoom still works,
and the scrollbar's width is added to the body's right padding so content
does not shift when the scrollbar disappears.
Signaturesfunction lockScroll(opts?: ScrollLockOptions): () => void; function scrollLockCount(): number;
lockScroll returns the unlock function; calling it twice is harmless.
Options
| Option | Type | Default | What it does |
|---|---|---|---|
removeScrollBar |
boolean |
true |
Hide the page's scrollbar (overflow: hidden, gap compensated). false keeps it on screen and blocks wheel, touch and key scrolling of the page instead. |
With the scrollbar removed, its width is published as --scrollbar-gap on
<html> for fixed elements that need the same compensation:
app/shared/styles/page.css.site-header { padding-right: calc(var(--space-4) + var(--scrollbar-gap, 0px)); }
A root with scrollbar-gutter: stable keeps its gutter, so no padding is
added and --scrollbar-gap is 0px.
With removeScrollBar: false the page does not scroll by wheel, touch or
keys, while a scroller that can still move in that direction takes the
gesture as usual. A scroll key is left alone only when the focused element
itself uses it: a field, a slider's arrows, a button's Space. A pinch
(Ctrl+wheel, two fingers) is never blocked. When any held lock removes the
bar, the page uses overflow: hidden as above.
In a template of your own
app/shared/templates/overlay/index.ehtmlimport { lockScroll } from "@elements/ui/behaviors"; interface OverlayState { unlock?: () => void; } <Overlay (open: boolean = false, private ui: OverlayState = {})> <div e:if={open} class="overlay" oninsert={() => ui.unlock = lockScroll()} onremove={() => ui.unlock?.()}> <slot/> </div> </Overlay>
Writes
data-scroll-locked on <body> while any lock is held. With the scrollbar
removed: overflow: hidden on <html>, the scrollbar width added to the
body's padding-right, and --scrollbar-gap on <html>. With
removeScrollBar: false, none of those: wheel, touch and key listeners on
the document instead.
Used by
Combobox (opens in a new tab), Dialog (opens in a new tab), DropdownMenu (opens in a new tab), ContextMenu (opens in a new tab), Menubar (opens in a new tab), Popover (opens in a new tab), Select (opens in a new tab).