ycs77 / headlessui-float

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

Error: Did you forget to passthrough the `ref` to the actual DOM node? when content is in separate component #78

Closed Spence1115 closed 1 year ago

Spence1115 commented 1 year ago

Use Version Use version when bugs appear:

Describe the bug Using Listbox, if I extract the Listbox.Options into a reusable component, I get the following error when clicking on the button to open the dropdown

Error: Did you forget to passthrough therefto the actual DOM node?

To Reproduce

import { Listbox } from '@headlessui/react';
import { Float } from '@headlessui-float/react';

export default function App() {
  type Option = {
    label: string;
    value: number;
  };

  interface SelectionOptionsProps {
    options: Option[];
  }

  function SelectionOptions({ options }: SelectionOptionsProps) {
    return (
      <Listbox.Options>
        {options.map((option) => (
          <Listbox.Option value={option}>{option.label}</Listbox.Option>
        ))}
      </Listbox.Options>
    );
  }

  const options = [
    {
      label: 'First',
      value: 1,
    },
    {
      label: 'Second',
      value: 2,
    },
  ];

  return (
    <>
      <div>
        <Listbox>
          <Float>
            <Listbox.Button>Dropdown failing here</Listbox.Button>
            <SelectionOptions options={options} />
          </Float>
        </Listbox>
      </div>
      <div>
        <Listbox>
          <Float>
            <Listbox.Button>Dropdown working here</Listbox.Button>
            <Listbox.Options>
              {options.map((option) => (
                <Listbox.Option value={option}>{option.label}</Listbox.Option>
              ))}
            </Listbox.Options>
          </Float>
        </Listbox>
      </div>
    </>
  );
}

https://stackblitz.com/edit/github-57al64?file=src%2FApp.tsx

  1. Click Dropdown working here
  2. Dropdown opens
  3. Click Dropdown failing here
  4. See errors in console instead of the dropdown rendered

Expected behavior I should be able to extract the dropdown content into another component and it still work

Spence1115 commented 1 year ago

@ycs77 I made a forked PR with a test to reproduce this bug https://github.com/ycs77/headlessui-float/pull/79

Spence1115 commented 1 year ago

Solved my own issue, needed a forwardRef.

import { Listbox } from '@headlessui/react';
import { Float } from '@headlessui-float/react';
import React from 'react';

export default function App() {
  type Option = {
    label: string;
    value: number;
  };

  interface SelectionOptionsProps {
    options: Option[];
  }

  const SelectionOptions = React.forwardRef(
    ({ options }: SelectionOptionsProps, ref) => (
      <Listbox.Options ref={ref}>
        {options.map((option) => (
          <Listbox.Option value={option}>{option.label}</Listbox.Option>
        ))}
      </Listbox.Options>
    )
  );

  const options = [
    {
      label: 'First',
      value: 1,
    },
    {
      label: 'Second',
      value: 2,
    },
  ];

  return (
    <>
      <div>
        <Listbox>
          <Float>
            <Listbox.Button>Dropdown failing here</Listbox.Button>
            <SelectionOptions options={options} />
          </Float>
        </Listbox>
      </div>
      <div>
        <Listbox>
          <Float>
            <Listbox.Button>Dropdown working here</Listbox.Button>
            <Listbox.Options>
              {options.map((option) => (
                <Listbox.Option value={option}>{option.label}</Listbox.Option>
              ))}
            </Listbox.Options>
          </Float>
        </Listbox>
      </div>
    </>
  );
}