I have a custom modal component. When it's open, there is no scrolling whatsoever in the background.
I tried this code below:
componentDidMount() {
document.body.style.overflow = 'hidden';
}
componentWillUnmount() {
document.body.style.overflow = 'unset';
}
Which seems to work at first, but when I use the modal component, in another page, there is no scroll even when the modal is closed.
Is there a better solution for this?
My modal component:
export class Modal extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
document.body.style.overflow = 'hidden';
}
componentWillUnmount() {
document.body.style.overflow = 'unset';
}
render() {
return (
<React.Fragment>
{this.props.showAt ?
this.props.show ?
<div style={style} className={`${this.props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!this.props.showAt ? styles.modalWhiteFixed : ""}`}>
{this.props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{this.props.children}
</div>
: null
:
this.props.show ?
<div className={`${this.props.className} ${styles.modal}`}>
<div style={style} className={`${this.props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!this.props.showAt ? styles.modalWhiteFixed : ""}`}>
{this.props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{this.props.children}
</div>
</div> :
null}
</React.Fragment>
)
}
}
Approach: A simple solution to this problem is to set the value of the “overflow” property of the body element to “hidden” whenever the modal is opened, which disables the scroll on the selected element.
To prevent scrolling using CSS on React rendered components, we can set the overflow CSS property to hidden with JavaScript. to set the overflow CSS of the body element to hidden when the component mounts with: document. body.
Use state to track if the Modal is open and only hide scroll if it's true. Since you're using document.body.style.overflow = 'hidden'
in componentDidMount
, the component still gets mounted which calls the lifecycle method that hides the scroll on body.
export class Modal extends React.Component { constructor(props) { super(props); this.state = { open:false } } componentDidMount() { if(this.state.open){ document.body.style.overflow = 'hidden'; } } componentWillUnmount() { document.body.style.overflow = 'unset'; } render() { return ( <React.Fragment> {this.props.showAt ? this.props.show ? <div style={style} className={`${this.props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!this.props.showAt ? styles.modalWhiteFixed : ""}`}> {this.props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null} {this.props.children} </div> : null : this.props.show ? <div className={`${this.props.className} ${styles.modal}`}> <div style={style} className={`${this.props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!this.props.showAt ? styles.modalWhiteFixed : ""}`}> {this.props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null} {this.props.children} </div> </div> : null} </React.Fragment> ) } }
in functional component for when mount or unmount
useEffect(() => { document.body.style.overflow = 'hidden'; return ()=> document.body.style.overflow = 'unset'; }, []);
or when show
is change or etc
useEffect(() => { show && document.body.style.overflow = 'hidden'; !show && document.body.style.overflow = 'unset'; }, [show ]);
Here is a custom hook you can use for functional components.
import { useEffect } from 'react';
export const useDisableBodyScroll = (open) => {
useEffect(() => {
if (open) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = 'unset';
}
}, [open]);
};
export const Modal = (props) => {
useDisableBodyScroll(props.show);
return (
<React.Fragment>
{props.showAt ?
props.show ?
<div style={style} className={`${props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!props.showAt ? styles.modalWhiteFixed : ""}`}>
{props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{props.children}
</div>
: null
:
props.show ?
<div className={`${props.className} ${styles.modal}`}>
<div style={style} className={`${props.sectionName} ${modalTypeStyle ? modalTypeStyle : styles.modalWhite} ${modalTypeSize ? modalTypeSize : styles.modalSmall} ${!props.showAt ? styles.modalWhiteFixed : ""}`}>
{props.arrowShape ? <div className={arrowTypeStyle ? arrowTypeStyle : styles.triangleToprightWhite} /> : null}
{props.children}
</div>
</div> :
null}
</React.Fragment>
)
}
}
In functional components if the browser move due to hiding/showing scroll.
useEffect(() => {
if (show) {
document.body.style.overflow = 'hidden';
document.body.style.paddingRight = '15px';
}
return () => {
document.body.style.overflow = 'unset';
document.body.style.paddingRight = '0px';
};
}, [show]);
I have 2 functions to handle this, when open modal and when close modal
openModal(){
this.setState({
isModalOpen: true
})
document.body.style.overflow = 'hidden';
}
closeModal(){
this.setState({
isModalOpen: false
})
document.body.style.overflow = 'unset';
}
For me it works when I check the show of the show. Example in functional component
useEffect(() => {
if (show) document.body.style.overflow = 'hidden';
else document.body.style.overflow = 'visible';
}, [show]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With