I’m trying to create a pop up subscription box which closes whenever one clicks on the close button or clicks anywhere outside the pop up. I’ve created a modal component and a state showModal
which is used to toggle the visibility of this Modal. I have tried to add setShowModal(false)
to the outer div
element but that just disables the whole modal. What can be done to close the modal whenever we click outside the modal. This is how my main page looks
const [showModal, setShowModal] = useState(false); return ( <> <div className="homepage" style={{ filter: showModal ? "blur(8px)" : "none", minHeight:"80vh", }} > <section className="homepage-hero" style={{ paddingBottom:"-2rem", minHeight:"100vh" }} > <div className="hero-body"> <div className="container"> <div className="columns"> <div className="column "> <h1> <span className="heading"> Finance <br /> Scheme </span> <br /> </h1> <p> Lorem Ipsum </p> <div className="is-hidden-tablet"> </div> <div className="button-group"> <button style={{ fontWeight: "600", padding: "0.75em 1.9em", borderRadius: "0px", color: "white", backgroundColor: "#24ca7a", border: "1px solid #24ca7a", cursor: "pointer", }} onClick={() => setShowModal(true)} > Download </button> </div> </div> </div> </div> </div> </section> </div> {showModal && ( <Modal modalId="signup-modal" onClose={() => setShowModal(false)} canDismiss={false} modalWidth="70%" style={{position:"fixed", top:"20", minHeight:"50vh"}} > <div className="contact-us" style={{ margin:"20px"}}> <section className="contact-form" > <div className="container"> <div className="columns is-8 "> <div className="column is-half-desktop is-full-mobile container-content" style={{ boxShadow: "none" }} > {submitted ? ( <div className="success"> <img src={confirmedIllus} alt="" /> <h2>Your details have been submitted successfully!</h2> </div> ) : ( <form onSubmit={handleOnSubmit} id="contact-form" > <h1 className="heading" style={{ fontSize: "2rem" }}> Your Details </h1> <br /> <div className="field"> <label className="label">Name</label> <div className="control"> <input className="input" id="name" value={name} type="text" placeholder="Your Full Name" onChange={(e) => setName(e.target.value)} required /> </div> </div> <div className="field"> <label className="label">Email</label> <div className="control "> <input className={`input ${isDanger}`} id="email" value={email} type="email" onChange={handleOnChange} placeholder="Your Email" required /> {!validEmail && isDanger ? ( <span className="icon is-small is-right"> <i className="material-icons-round">warning</i> </span> ) : ( " " )} </div> {!validEmail && isDanger ? ( <p className="help is-danger">{emailMessage}</p> ) : ( "" )} </div> <div className="field is-grouped submit-button-group"> <div className="control"> <button style={{ cursor: !validEmail ? "not-allowed" : "pointer", }} className="button submit-button" id="submit-form" > Submit </button> </div> </div> </form> )} </div> <div className="column is-half-desktop is-full-mobile " > <img src="/images/Ebook.svg" className="is-hidden-mobile" style={{ width: "70%", marginTop: "40%" }} /> <div className=" font-blue bottom-text"> Fill your details to download the free <b> Ebook </b> </div> </div> </div> </div> </section> </div> </Modal> )} </> );
Advertisement
Answer
You can use the useOnClickOutside
hook. This hook allows you to detect clicks outside of a specified element.
You have to import the followings
Create a ref that we add to the element for which we want to detect outside clicks
const ref = useRef();
State for our modal
const [showModal, setShowModal] = useState(false);
Call hook passing in the ref and a function to call on outside click
useOnClickOutside(ref, () => setShowModal(false));
render here
return(…);
//Hook import { useEffect } from 'react'; export default function useOnClickOutside(ref, handler) { useEffect( () => { const listener = (event) => { // Do nothing if clicking ref's element or descendent elements if (!ref.current || ref.current.contains(event.target)) { return; } handler(event); }; document.addEventListener("mousedown", listener); document.addEventListener("touchstart", listener); return () => { document.removeEventListener("mousedown", listener); document.removeEventListener("touchstart", listener); }; }, // Add ref and handler to effect dependencies // It's worth noting that because the passed-in handler is a new ... // ... function on every render that will cause this effect ... // ... callback/cleanup to run every render. It's not a big deal ... // ... but to optimize you can wrap handler in useCallback before ... // ... passing it into this hook. [ref, handler] ); }
See related repl output here – https://spanishhotloaderprogram.thelovekesh.repl.co/