React.js: How to close headlessui Disclosure modal from code?

Viewed 2177

I encountered an issue trying to close the headlessui Disclosure modal inside the panel. My goal is to have a button inside the panel which can close the modal.
The way I tried to solve this problem is doing it manually using useRef, but it works partially.
After opening the panel for the first time, you can close the modal but if you try to open it again, it doesn't work.
Can't figure out how to solve this issue.
Any help will be appreciated.
Here is the codesandbox link

And here is the code

import { Disclosure } from "@headlessui/react";
import React, { useState, useRef } from "react";

import CloseIcon from "@material-ui/icons/Close";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
const App = () => {
  const [isClosed, setIsClosed] = useState(false);

  const modalRef = useRef(null);
  const hideModalHandler = (e) => {
    e.preventDefault();
    modalRef.current?.click();
    setIsClosed(!isClosed);
  };

  return (
    <Disclosure>
      {({ open }) => (
        <div ref={modalRef}>
          <Disclosure.Button>
            <span>modal</span>
            <ExpandMoreIcon />
          </Disclosure.Button>

          {!isClosed && (
            <Disclosure.Panel>
              <CloseIcon onClick={hideModalHandler} />
              <div>name</div>
            </Disclosure.Panel>
          )}
        </div>
      )}
    </Disclosure>
  );
};

export default App;

2 Answers

I haven't used headlessui Disclosure but I see that the function hideModalHandler isn't actually hiding but toggling. Did you mean setIsClosed(true) instead of setIsClosed(!isClosed)?

Also, after a quick look at the documentation, have you tried using the close from the headlessui Disclosure? You don't need useRef

Use the state, and wrap the disclosure button into a DIV with onClick and some ID string to identify what disclosure must be open. Something like this (works for multiple disclosures):

const [keyOfOpenDisclosure, setKeyOfOpenDisclosure] = useState('')

const toggleDisclosure = (key: string) => {
    setKeyOfOpenDisclosure((prev) => (prev !== key ? key : ''))
}

...

<Disclosure>
    <div onClick={() => toggleDisclosure(someId)}>
        <Disclosure.Button>
            Text of disclosure button
        </Disclosure.Button>
    </div>
    <Transition
      show={someId === keyOfOpenDisclosure}
...
Related