fefe
fefe

Reputation: 9065

React Modal close if is clicked outside of content

I have created a custom react modal component and I would like refactor to be able to track the outside clicks of modal content and to be able to close modal My code looks as it follows. And I search for a workaround to remove the create portal if click is outside of popup container,

import React from "react";
import ReactDOM from "react-dom";


const Hint = (props) => {
  const ToggleContent = ({ toggle, content }) => {
    const [isShown, setIsShown] = React.useState(false);
    const hide = () => setIsShown(false);
    const show = () => setIsShown(true);

    return (
      <React.Fragment>
        {toggle(show)}
        {isShown && content(hide)}
      </React.Fragment>
    );
  };

  const Modal = ({ children }) => {
    return ReactDOM.createPortal(
      <div className="modal">{children}</div>,
      document.body
    );
  };

  return (
    <div className={"hint"}>
      <ToggleContent
        toggle={(show) => (
          <div className={"hint__icon"} onClick={show}>
         
            {props.hintLabel ? (
              <div className={"hint__label-text"}>{props.hintLabel}</div>
            ) : null}
          </div>
        )}
        content={(hide) => (
          <div className={"modal__body"}>
            <Modal>
              <div className={"popup"}>
                <div className={"popup__wrapper"}>
                  <div
                    className={"popup__content"}
                    dangerouslySetInnerHTML={{ __html: props.content }}
                  ></div>
                </div>
                <button onClick={hide} type="button" className="close">
                  X
                </button>
              </div>
            </Modal>
          </div>
        )}
      />
    </div>
  );
};

ReactDOM.render(
    <Hint hintLabel="test" content="teasasd ajsdghajsdg" />,
    document.getElementById("app")
  );
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="app"></div>

Upvotes: 5

Views: 11050

Answers (2)

Rahul Shakya
Rahul Shakya

Reputation: 1425

use react-native-modal package where there is a props call onBackDrop press which will do your job

Or if you dont want to add react-native-modal package there is work around

<Modal visible={showModal} transparent>
        <TouchableOpacity
          onPress={() => setShowModal(false)}
          style={{
            position: 'absolute',
            width: wp(100),
            height: hp(100),
            backgroundColor: allColor.darkGreyOpacity,
          }}></TouchableOpacity>
          <View>
          //you code goes herere
          </View>
</Modal>
``

Upvotes: 0

Igor Kamyshev
Igor Kamyshev

Reputation: 149

I guess, this hook can help you.

export const useClickOutside = (
  insideRefs,
  isVisible,
  onClose,
) => {
  useEffect(() => {
    const handleWindowClick = (event) => {
      const someRefContainTarget = insideRefs
        .filter((ref) => ref.current)
        .some((ref) => ref.current.contains(event.target));

      if (someRefContainTarget) {
        return;
      }

      if (!isVisible) {
        return;
      }

      if (onClose) {
        onClose();
      }
    };

    if (isVisible) {
      window.addEventListener('click', handleWindowClick);
    }

    return () => {
      if (isVisible) {
        window.removeEventListener('click', handleWindowClick);
      }
    };
  }, [isVisible, onClose]);
};

Just pass onClose-handler, visibility-state (isShown in your case) and refs for all inside elements.

Upvotes: 6

Related Questions