Headless UI modal (dialog component) how do I close when clicking on children?

151 views Asked by At

How do I close a modal window by clicking on any child link?

import { Dialog } from "@headlessui/react"

const [modalIsOpen, setModalIsOpen] = useState<boolean>(false)

<Dialog open={modalIsOpen} onClose={() => setModalIsOpen(false)}>
        <div className="fixed inset-0 overflow-y-auto">
          <Dialog.Panel as="div" className="absolute right-5 top-10">
            <MobileLkMenu />
          </Dialog.Panel>
        </div>
      </Dialog>

Now the modal window is closed only for a click outside.

Also, if you hang the event handler on Dialog.Panel, the modal window will close when click on its body, but not on the link. How do I make the link close?

Dynamic options are rendered in the modal window (sometimes a large number). There is no way to throw a callback into each option.

enter image description here

1

There are 1 answers

2
Kyle Xyian Dilbeck On

There are a few ways to solve this. For a simple example, you can use the onClose callback provided by Dialog from @headlessui/react. However, the onClose callback should be triggered from within the modal content itself, not from the Dialog.Panel.

Here's how you can modify your code to achieve this:

import { Dialog } from "@headlessui/react";
import { useState } from "react";

const ModalComponent = () => {
  const [modalIsOpen, setModalIsOpen] = useState<boolean>(false);

  return (
    <Dialog open={modalIsOpen} onClose={() => setModalIsOpen(false)}>
      <div className="fixed inset-0 overflow-y-auto">
        <Dialog.Panel as="div" className="absolute right-5 top-10">
          <div>
            <p>Modal Content</p>
            <a href="#" onClick={() => setModalIsOpen(false)}>Close Modal</a>
          </div>
        </Dialog.Panel>
      </div>
    </Dialog>
  );
};

export default ModalComponent;

In this example, clicking on the "Close Modal" link inside the modal content will trigger the onClick event, which in turn calls setModalIsOpen(false), closing the modal window.


without callbacks / useRef update:

import { Dialog } from "@headlessui/react";
import { useState, useRef, useEffect } from "react";

const ModalComponent = () => {
  const [modalIsOpen, setModalIsOpen] = useState<boolean>(false);
  const modalRef = useRef(null);

  useEffect(() => {
    const handleClickOutside = (event) => {
      if (modalRef.current && !modalRef.current.contains(event.target)) {
        setModalIsOpen(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  return (
    <Dialog open={modalIsOpen} onClose={() => setModalIsOpen(false)}>
      <div ref={modalRef} className="fixed inset-0 overflow-y-auto">
        <Dialog.Panel as="div" className="absolute right-5 top-10">
          <MobileLkMenu />
        </Dialog.Panel>
      </div>
    </Dialog>
  );
};

export default ModalComponent;