ycs77 / headlessui-float

Easily use Headless UI with Floating UI to position floating elements.
https://headlessui-float.vercel.app
MIT License
342 stars 11 forks source link

Pass custom `root` to `<Float>` #91

Closed franzheidl closed 7 months ago

franzheidl commented 8 months ago

Hi, Often when I render floated content using <Float>, I need the floated element to be rendered somewhere outside of the parent node of my component in the document tree.

When I use a portal like <Float portal [...]> the floating element will be rendered last up in the document.body which will result in the floating element being rendered outside my App root element and outside the scope of my styles. I have not found a way to customize the parent node of the portal.

In order to resolve the issue I would like to be able to pass an element or ref to <Float> as a parent for the portal, ideally in a similar or identical way to headless-ui FloatingPortal.

Similar to headless-ui FloatingPortal I would love a possible root prop to accept an element/node, a ref, or even the id of a parent element to render the content in (Having id as a seperate prop just as headless-ui does would be just as good).

Thank you already in advance for any pointers or for considering the feature.

ycs77 commented 8 months ago

Hi @franzheidl, Please give me a scenario and an example with code (like github repo, codesandbox, stackblitz...) and tell me when this change would be needed.

franzheidl commented 7 months ago

Hi, thanks a lot for getting back!

I finally managed to achieve what I need by using <Float> in composable mode, and render the <Float.Content> part into a portal using a hook that we provide ourselves (this could be done manually of course, too), not using the inbuilt portal functionality of <Float> (incomplete, but should get the concept across):

import { createPortal } from "react-dom"
import { Listbox } from "@headlessui/react"
import { Float } from "@headlessui-float/react"
import { usePortalRef } from "../PortalProvider/"  // This is a PortalProvider we wrote that creates a portal parent where we want it in the dom, and exposes a hook to reference the specified element

const middleware = [...]. // Float configuration
const portalParentRef = usePortalRef() // call our hook that creates a portal parent where we want it and returns a reference 

export const Select({...}} => {

[...]

return (
  <div className="wrapper">
    <Listbox>
      <Float composable adaptiveWidth middleware={middleware}>

        <Float.Reference>
          <Listbox.Button>
            [...]
          </Listbox.Button>

        </Float.Reference>

          { createPortal(
             <Float.Content>
               <Listbox.Options>
                 [...]
               </Listbox.Options>
             </Float.Content>,
              portalParentRef ? portalParentRef : document.body
          )}

        </Float.Reference>

      </Float>
    </Listbox>
  </div>
)

}

This seems to work nicely and does what we want, so the feature request is kind of void or would be a convenience feature, but not really necessary for us anymore, so you can close the request if you want.

I am posting this here as a reference for others who might apporach you with the same or similar request.

Thank you a lot for your work! 👍

ycs77 commented 7 months ago

OK, I'll close this issue.