Home > Software design >  Hide modal on click outside in react hooks
Hide modal on click outside in react hooks

Time:01-08

i have a modal component in my react app and i need to close it on click outside

import React from "react";
import ReactDOM from "react-dom";
import style from "./Modal.module.scss";

const Modal = ({ isShowing, hide, childrenContent, childrenHeader }) =>
  isShowing
    ? ReactDOM.createPortal(
        <React.Fragment>
          <div className={style.modalOverlay} />
          <div
            className={style.modalWrapper}
            aria-modal
            aria-hidden
            tabIndex={-1}
            role="dialog"
          >
            <div className={style.modal}>
              <div className={style.modalHeader}>
                {childrenHeader}
                <button
                  type="button"
                  className={style.modalCloseButton}
                  data-dismiss="modal"
                  aria-label="Close"
                  onClick={hide}
                >
                  <span aria-hidden="true">&times;</span>
                </button>
              </div>
              {childrenContent}
            </div>
          </div>
        </React.Fragment>,
        document.body
      )
    : null;

export default Modal;

i was try to use this solution but it's not work in my code, how can i fix it?

CodePudding user response:

Just a tip, when looking at the html you can use the native <dialog> tag, this is the semantically correct way to display a dialog type pop-up box, which yours looks to be.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog

Dialog has a showModal() method, and a .close() method. This would be a better way of displaying a pop-up type dialog, than using <div> tags. It also allows you to use the native HTML5 methods, rather than trying to provide a work around using React.

I would reccomend this method over trying to look for work arounds

CodePudding user response:

const Modal = ({ children, showModal, toggleModal }) => {
const wrapperRef = React.useRef(null);

const closeModal = React.useCallback(
({ target }) => {
  if (
    wrapperRef &&
    wrapperRef.current &&
    !wrapperRef.current.contains(target)
  ) {
    toggleModal();
  }
  },
  [toggleModal]
  );

  React.useEffect(() => { 
  document.addEventListener("click", closeModal, { capture: true });
  return () => {
  document.removeEventListener("click", closeModal, { capture: true });
  };
  }, [closeModal]);

  return showModal
  ? ReactDOM.createPortal(
    <>
          <div ref={wrapperRef} className="modal">
            {children}
          </div>
    </>,
    document.body
  )
 : null;
 };

Modal.propTypes = {
children: PropTypes.node.isRequired,
showModal: PropTypes.bool.isRequired,
toggleModal: PropTypes.func.isRequired
};

export default Modal;

in your parent component :

const Parent = () => {
const [showModal, setModalState] = React.useState(false);

const toggleModal = React.useCallback(() => {
setModalState((prevState) => !prevState);
}, []);

return (
<div>
  <Modal showModal={showModal} toggleModal={toggleModal}>
    <h1>Hello!</h1>
    ... some other childrens
    <button
      onClick={toggleModal}
    >
      Close
    </button>
  </Modal>
</div>
);
};
  • Related