Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't get access to ref on Transition.Child or Transition #273

Closed
dev-cyprium opened this issue Mar 8, 2021 · 9 comments · Fixed by #1116
Closed

Can't get access to ref on Transition.Child or Transition #273

dev-cyprium opened this issue Mar 8, 2021 · 9 comments · Fixed by #1116
Assignees

Comments

@dev-cyprium
Copy link

I'm trying to make a modal utility in React, and I wаnt to add code that allows clicking outside of the modal.

<Transition
              show={visible}
              className={clsx("fixed z-10 inset-0 overflow-y-auto")}
            >
              <div className="flex items-end justify-center msin-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
                <Transition.Child
                  enter="ease-out duration-300"
                  enterFrom="opacity-0"
                  enterTo="opacity-100"
                  leave="ease-in duration-200"
                  leaveFrom="opacity-100"
                  leaveTo="opacity-0"
                  className="fixed inset-0 transition-opacity"
                >
                  <div aria-hidden="true">
                    <div className="absolute inset-0 bg-gray-500 opacity-75"></div>
                  </div>
                </Transition.Child>

                {/* This element is to trick the browser into centering the modal contents. */}
                <span
                  className="hidden sm:inline-block sm:align-middle sm:h-screen"
                  aria-hidden="true"
                >
                  &#8203;
                </span>
                <Transition.Child
                  enter="ease-out duration-300"
                  enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
                  enterTo="opacity-100 translate-y-0 sm:scale-100"
                  leave="ease-in duration-200"
                  leaveFrom="opacity-100 translate-y-0 sm:scale-100"
                  leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
                  className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
                  role="dialog"
                  aria-modal="true"
                  aria-labelledby="modal-headline"
                >
...

What I wanted to do was attach a ref to my child so that I can detect whether or not the user has clicked outside the modal. This is however not possible, and I think it should be, as the <Transition.Child> creates a div for me. I'd like to be able to referece that div:

function MyComponent() {
   const ref = useRef(null);
   
   useEffect(() => {
    function handleClickOutside(event) {
      if (ref.current && !ref.current.contains(event.target)) {
          // user has clicked outside of modal...
      }
    }

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
   
   return <Transition><Transition.Child ref={ref}>...</Transition.Child></Transition>
}

This doesn't work, because Transition.Child and Transition components don't forward refs to the div.

@moiz-frost
Copy link

Facing a similar issue

@italodeandra
Copy link

This is extremely necessary.

@efrister
Copy link

Possible solutions:

  1. Use the Dialog component to have this functionality, alongside additional relevant functionality for modals, for free
  2. Use the ref that gets exposed by Transition and prevent it from rendering its own div, like so:
<Transition show={open} as={React.Fragment}>
      {(ref) => (
        <div ref={ref}></div>
      )}
</Transition>

Transition and Transition.Child both expose their ref like that. See e.g. the UI Docs for further reference.

@RobinMalfait
Copy link
Member

Possible solutions:

  1. Use the Dialog component to have this functionality, alongside additional relevant functionality for modals, for free
  2. Use the ref that gets exposed by Transition and prevent it from rendering its own div, like so:
<Transition show={open} as={React.Fragment}>
      {(ref) => (
        <div ref={ref}></div>
      )}
</Transition>

Transition and Transition.Child both expose their ref like that. See e.g. the UI Docs for further reference.

Going to comment on this real quick, because in the latest version (in develop branch) this is not the case anymore, because we now have the same API for every component.

That said, I'll make sure that every component will be able to expose a ref to the underlying DOM node if it makes sense!

@jaredloson
Copy link

@RobinMalfait What's the status of exposing refs for every component? I'm hoping that I'll be able to pass a ref prop to any of the Headless UI components that renders a top-level HTML element.

@RobinMalfait
Copy link
Member

This should be fixed by #1116, and will be available in the next release.

You can already try it using:

  • npm install @headlessui/react@insiders or yarn add @headlessui/react@insiders.

@ARkrOSClou
Copy link

ARkrOSClou commented May 18, 2022

This should be fixed by #1116, and will be available in the next release.

You can already try it using:

  • npm install @headlessui/react@insiders or yarn add @headlessui/react@insiders.

ref still doesn't work when used on <Transition.Child>
tested on @headlessui/react@^1.6.1 and @headlessui/react@insiders versions

@RobinMalfait
Copy link
Member

@ARkrOSClou create a new issue with a minimal reproduction CodeSandbox / repo attached.

@Ding-Fan
Copy link

same error 😢

@tailwindlabs tailwindlabs locked as resolved and limited conversation to collaborators Jul 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants