Security News
The Risks of Misguided Research in Supply Chain Security
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
body-scroll-lock
Advanced tools
Enables body scroll locking (for iOS Mobile and Tablet, Android, desktop Safari/Chrome/Firefox) without breaking scrolling of a target element (eg. modal/lightbox/flyouts/nav-menus)
The body-scroll-lock package is designed to disable scrolling on the body element of a webpage, typically used when a modal or overlay is open to prevent background scrolling. It provides a simple API to lock and unlock scroll on touch and non-touch devices.
Disable scrolling on the body
This feature allows you to disable scrolling on the body of the page. The target element is typically the modal or overlay that is currently active.
import { disableBodyScroll } from 'body-scroll-lock';
const targetElement = document.querySelector('#someElementId');
disableBodyScroll(targetElement);
Enable scrolling on the body
This feature re-enables scrolling on the body of the page. It is used when the modal or overlay is closed and normal page interaction is to be restored.
import { enableBodyScroll } from 'body-scroll-lock';
const targetElement = document.querySelector('#someElementId');
enableBodyScroll(targetElement);
Clear all body scroll locks
This function clears all locks on body scroll. It is useful when you need to ensure that all locks have been removed, for instance, during cleanup or unmounting of components.
import { clearAllBodyScrollLocks } from 'body-scroll-lock';
clearAllBodyScrollLocks();
This package provides similar functionality to body-scroll-lock but is specifically tailored for React applications. It offers a React component that can be wrapped around parts of the UI to prevent scrolling.
Similar to body-scroll-lock, scroll-lock is another package that prevents scrolling on the body element. It provides more customization options and methods for handling scroll locking.
no-scroll is a simpler and smaller package compared to body-scroll-lock. It provides basic functionality to stop scrolling on the body without additional features like handling touch events.
Enables body scroll locking (for iOS Mobile and Tablet, Android, desktop Safari/Chrome/Firefox) without breaking scrolling of a target element (eg. modal/lightbox/flyouts/nav-menus).
Features:
-webkit-overflow-scrolling: touch
still worksAren't the alternative approaches sufficient?
document.body.ontouchmove = (e) => { e.preventDefault(); return false; };
locks the
body scroll, but ALSO locks the scroll of a target element (eg. modal).overflow: hidden
on the body or html elements doesn't work for all browsersposition: fixed
approach causes the body scroll to resetLIGHT Package Size:
$ yarn add body-scroll-lock
or
$ npm install body-scroll-lock
You can also load via a <script src="lib/bodyScrollLock.js"></script>
tag (refer to the lib folder).
// 1. Import the functions
const bodyScrollLock = require('body-scroll-lock');
const disableBodyScroll = bodyScrollLock.disableBodyScroll;
const enableBodyScroll = bodyScrollLock.enableBodyScroll;
// 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
const targetElement = document.querySelector('#someElementId');
// 3. ...in some event handler after showing the target element...disable body scroll
disableBodyScroll(targetElement);
// 4. ...in some event handler after hiding the target element...
enableBodyScroll(targetElement);
// 1. Import the functions
import { disableBodyScroll, enableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock';
class SomeComponent extends React.Component {
targetElement = null;
componentDidMount() {
// 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
this.targetElement = document.querySelector('#targetElementId');
}
showTargetElement = () => {
// ... some logic to show target element
// 3. Disable body scroll
disableBodyScroll(this.targetElement);
};
hideTargetElement = () => {
// ... some logic to hide target element
// 4. Re-enable body scroll
enableBodyScroll(this.targetElement);
};
componentWillUnmount() {
// 5. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
// OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
// clicks a link which takes him/her to a different page within the app.
clearAllBodyScrollLocks();
}
render() {
return <div>some JSX to go here</div>;
}
}
// 1. Import the functions
import { disableBodyScroll, enableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock';
class SomeComponent extends React.Component {
// 2. Initialise your ref and targetElement here
targetRef = React.createRef();
targetElement = null;
componentDidMount() {
// 3. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
this.targetElement = this.targetRef.current;
}
showTargetElement = () => {
// ... some logic to show target element
// 4. Disable body scroll
disableBodyScroll(this.targetElement);
};
hideTargetElement = () => {
// ... some logic to hide target element
// 5. Re-enable body scroll
enableBodyScroll(this.targetElement);
};
componentWillUnmount() {
// 5. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
// OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
// clicks a link which takes him/her to a different page within the app.
clearAllBodyScrollLocks();
}
render() {
return (
// 6. Pass your ref with the reference to the targetElement to SomeOtherComponent
<SomeOtherComponent ref={this.targetRef}>some JSX to go here</SomeOtherComponent>
);
}
}
// 7. SomeOtherComponent needs to be a Class component to receive the ref (unless Hooks - https://reactjs.org/docs/hooks-faq.html#can-i-make-a-ref-to-a-function-component - are used).
class SomeOtherComponent extends React.Component {
componentDidMount() {
// Your logic on mount goes here
}
// 8. BSL will be applied to div below in SomeOtherComponent and persist scrolling for the container
render() {
return <div>some JSX to go here</div>;
}
}
import { Component, ElementRef, OnDestroy, ViewChild } from "@angular/core";
// 1. Import the functions
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks
} from "body-scroll-lock";
@Component({
selector: "app-scroll-block",
templateUrl: "./scroll-block.component.html",
styleUrls: ["./scroll-block.component.css"]
})
export class SomeComponent implements OnDestroy {
// 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
@ViewChild("scrollTarget") scrollTarget: ElementRef;
showTargetElement() {
// ... some logic to show target element
// 3. Disable body scroll
disableBodyScroll(this.scrollTarget.nativeElement);
}
hideTargetElement() {
// ... some logic to hide target element
// 4. Re-enable body scroll
enableBodyScroll(this.scrollTarget.nativeElement);
}
ngOnDestroy() {
// 5. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
// OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
// clicks a link which takes him/her to a different page within the app.
clearAllBodyScrollLocks();
}
}
In the html:
<head>
<script src="some-path-where-you-dump-the-javascript-libraries/lib/bodyScrollLock.js"></script>
</head>
Then in the javascript:
// 1. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
const targetElement = document.querySelector('#someElementId');
// 2. ...in some event handler after showing the target element...disable body scroll
bodyScrollLock.disableBodyScroll(targetElement);
// 3. ...in some event handler after hiding the target element...
bodyScrollLock.enableBodyScroll(targetElement);
// 4. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
bodyScrollLock.clearAllBodyScrollLocks();
Check out the demo, powered by Vercel.
Function | Arguments | Return | Description |
---|---|---|---|
disableBodyScroll | targetElement: HTMLElement options: BodyScrollOptions | void | Disables body scroll while enabling scroll on target element |
enableBodyScroll | targetElement: HTMLElement | void | Enables body scroll and removing listeners on target element |
clearAllBodyScrollLocks | null | void | Clears all scroll locks |
optional, default: false
If the overflow property of the body is set to hidden, the body widens by the width of the scrollbar. This produces an
unpleasant flickering effect, especially on websites with centered content. If the reserveScrollBarGap
option is set,
this gap is filled by a padding-right
on the body element. If disableBodyScroll
is called for the last target element,
or clearAllBodyScrollLocks
is called, the padding-right
is automatically reset to the previous value.
import { disableBodyScroll } from 'body-scroll-lock';
import type { BodyScrollOptions } from 'body-scroll-lock';
const options: BodyScrollOptions = {
reserveScrollBarGap: true,
};
disableBodyScroll(targetElement, options);
optional, default: undefined
To disable scrolling on iOS, disableBodyScroll
prevents touchmove
events.
However, there are cases where you have called disableBodyScroll
on an
element, but its children still require touchmove
events to function.
See below for 2 use cases:
disableBodyScroll(container, {
allowTouchMove: el => el.tagName === 'TEXTAREA',
});
Javascript:
disableBodyScroll(container, {
allowTouchMove: el => {
while (el && el !== document.body) {
if (el.getAttribute('body-scroll-lock-ignore') !== null) {
return true;
}
el = el.parentElement;
}
},
});
Html:
<div id="container">
<div id="scrolling-map" body-scroll-lock-ignore>
...
</div>
</div>
https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177 https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi
Refer to the releases page.
FAQs
Enables body scroll locking (for iOS Mobile and Tablet, Android, desktop Safari/Chrome/Firefox) without breaking scrolling of a target element (eg. modal/lightbox/flyouts/nav-menus)
The npm package body-scroll-lock receives a total of 624,461 weekly downloads. As such, body-scroll-lock popularity was classified as popular.
We found that body-scroll-lock demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.
Security News
pnpm 10 blocks lifecycle scripts by default to improve security, addressing supply chain attack risks but sparking debate over compatibility and workflow changes.