Material UI Autocomplete virtualization w/ react-virtuoso

2.4k Views Asked by At

I have an almost working implementation of Material UI Autocomplete with the dropdown list virtualizised with react-virtuoso.

The issue I'm seeing at the moment is that when navigating upwards (0:25 in the video), the list doesn't move past the topmost item although the component seems to think it moving upwards.

It would seem like internally the list is moving upwards, but the gui isn't updated to reflect this. This is apparent when ⬇️ is pressed after pressing ⬆️: it takes as many ⬇️'s as there were ⬆️'s before the topmost item is highlighted again. The expected behavior is to scroll up as with a non-virtualized list, not sure if this is an issue with the react-virtuoso setup or if this is an issue with the Autocomplete component or this setup combining both.

A video of this issue in action can be found in this GitHub issue or directly here.

Thanks!

edit: here is a codesanbox of the issue: https://codesandbox.io/s/material-demo-forked-r6i2y?file=/demo.tsx

1

There are 1 best solutions below

3
On

I am using Virtuoso for mui autocomplete, just for a simple use case I dont support groups and stuff but is not hard to add to the code. The only thing I do is providing a custom ListboxComponent..the only hack I do is to get the computed maxHeight from the parent as I couldnt figure out how to make the height work correctly on resize

const ListboxComponent = forwardRef<HTMLUListElement>(({ children, ...rest }, ref) => {
  const data = children as ReactElement[];
  const localRef = useRef<string>('200px');

  return (
    <ul
      ref={reference => {
        const maxHeight = reference ? getComputedStyle(reference).maxHeight : null;
        if (maxHeight && maxHeight !== localRef.current) {
          localRef.current = maxHeight;
        }

        if (typeof ref === 'function') {
          ref(reference);
        }
      }}
      {...rest}
    >
      <Virtuoso
        style={{ height: localRef.current }}
        data={data}
        itemContent={(index, child) => {
          return cloneElement(child, { index });
        }}
      />
    </ul>
  );
}) as ComponentType<HTMLAttributes<HTMLElement>>;