ycs77 / headlessui-float

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

Accept `className` as part of FloatProps #13

Closed JesusTheHun closed 1 year ago

JesusTheHun commented 1 year ago

Is your feature request related to a problem? Please describe.

I'm using a combobox that uses all space available. Right now Float renders a blank div by default, meaning that its width will be width of its content. I want the width of the Float div to take all the space available.

So right now I have to create a dumb component and pass it to Float:

const FullWidthDiv: React.FC = ({children}) => <div className='w-full'>{children}</div>;
<Float as={FullWidthDiv} />

It feel like unnecessary work and accepting/passing className to the div would be more intuitive. Maybe disable (or trigger a warning) that if as is provided because the element itself may not accept className as a prop.

ycs77 commented 1 year ago

Hi @JesusTheHun

Can you please provide minimal examples (using like github repo, codesandbox, stackblitz..., and suggest can use the Vite & React scaffolding: https://vite.new/react) with the ComboBox component? because I don't know your intention 😅.

JesusTheHun commented 1 year ago

Stackblitz : https://stackblitz.com/edit/github-k6mhmk?file=src/components/ExampleComboboxWithAs.tsx

Check the DummyDiv at the end of the file. I have to create a dummy div just to add some classes. It would be nice to just pass them to the Float component :

<Float className={'w-full'}> ... </Float>

// Instead of

const MyCustomDiv = ({ children }) => <div className={'w-full'}>{children}</div>;
<Float as={MyCustomDiv}> ... </Float>
ycs77 commented 1 year ago

I think you're going to make a fullscreen Modal?

If that's the case, Headless UI Float is not suitable for such a thing. This package is a wrapper for Floating UI, the purpose is to create floating elements.

If you want to create a fullscreen Modal, it is recommended to use the Dialog / Modal component of Headless UI or other Modal packages.

JesusTheHun commented 1 year ago

No I'm not. I just want my option list to be the same width as my button. So I need to tell the float to take all the space available.

ycs77 commented 1 year ago

You can use this to set the list to be the width same as the button.

First, you have to wrap the <Float> with a <div> containing the relative and the width class, set the as={Fragment} prop of <Float>, final set the options list and button width to full (w-full).

import { Fragment } from 'react'

<Listbox>
  <div className="relative w-[260px]">
    <Float placement="bottom" offset={4} as={Fragment}>
      <Listbox.Button className="w-full ...">
        ...
      </Listbox.Button>

      <Listbox.Options className="w-full ...">
        ...
      </Listbox.Options>
    </Float>
  </div>
</Listbox>

If you want to set the width as button self width, you can use the inline-block for the wrapper:

<Listbox>
  <div className="relative inline-block">
    <Float>...</Float>
  </div>
</Listbox>

Or wrap a flexbox out fo the <Listbox>:

<div className="flex items-center">
  <Listbox>
    <div className="relative">
      <Float>...</Float>
    </div>
  </Listbox>
</div>

Reference from Headless UI Listbox example: https://headlessui.com/react/listbox

JesusTheHun commented 1 year ago

Your example could work, if we didn't circle back to #16 . Using Fragment the position is messed up, in my case the position ignores the shift.