Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Prevent scroll when modal is open

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>
    )
  }
}
like image 872
RCohen Avatar asked Mar 04 '19 18:03

RCohen


People also ask

How do I disable scrolling when Modal is open?

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.

How do I block the scroll react?

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.


6 Answers

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>     )   } } 
like image 143
Hemant Parashar Avatar answered Sep 20 '22 14:09

Hemant Parashar


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 ]); 
like image 27
Mehran Motiee Avatar answered Sep 19 '22 14:09

Mehran Motiee


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>
    )
  }
}

like image 31
John Franke Avatar answered Sep 18 '22 14:09

John Franke


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]);
like image 33
Nervall Avatar answered Sep 18 '22 14:09

Nervall


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';
    }
like image 45
Malnav Avatar answered Sep 19 '22 14:09

Malnav


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]);
like image 33
Ivan Oliveira Avatar answered Sep 20 '22 14:09

Ivan Oliveira