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

Combobox option list scrolling problem starting from v1.7.5 #2441

Closed
AnnaYuS opened this issue Apr 18, 2023 · 25 comments · Fixed by #2740 or #2779
Closed

Combobox option list scrolling problem starting from v1.7.5 #2441

AnnaYuS opened this issue Apr 18, 2023 · 25 comments · Fixed by #2740 or #2779
Assignees

Comments

@AnnaYuS
Copy link

AnnaYuS commented Apr 18, 2023

What package within Headless UI are you using?

@headlessui/vue

What version of that package are you using?

v1.7.5 and up

What browser are you using?

Firefox, Safari

Reproduction URL
https://stackblitz.com/edit/vue-gvtwnj?file=src/components/HelloWorld.vue

v1.7.4

Screen.Recording.2023-04-17.at.13.04.14.mov

v1.7.5

Screen.Recording.2023-04-17.at.13.03.48.mov

Describe your issue
Starting from v.1.7.5 there is a problem with the scroll when virtual list is used with Combobox options.
As was mentioned in this issue, the virtual lists don't work well with headless ui at the moment, but perhaps there is something that can be fixed in this case? Or maybe there is some sort of a workaround? This might have something to do with these changes
For now we had to pin v1.7.4, but we'd really like to upgrade to get all the fixes and new stuff
Before the upgrade to v1.7.5 the virtual lists weren't working perfectly, but they were more usable, and now scrolling is too problematic.
Your feedback would be greatly appreciated 🙏

@something123something
Copy link

so did u get a workaround?/fix/used a different library?

@yakobe
Copy link

yakobe commented May 11, 2023

Perhaps this is just a problem with the hold prop on ComboboxOptions? (see #2490)

image

When this is set to false i expect the active option to be deactivated when i scroll away from it. However, it currently stays active and then scrolls back to it.

@thecrypticace is there a way we can get around this problem. If we cannot "unset" thye active option then we have no way to use the combobox with large amounts of options 😭

@nielseulink
Copy link

I have the exact same issue after combining an listbox or combobox with useVirtualList. Is there any other workaround/fix besides locking the version down to 1.7.4?

@AnnaYuS
Copy link
Author

AnnaYuS commented Jun 26, 2023

I haven't found any workarounds 😞 Looking at alternatives to Headless UI at the moment like zagjs, and also someone working on Radix for Vue looks promising

@AnnaYuS
Copy link
Author

AnnaYuS commented Jul 11, 2023

Headless ui is awesome and widely used, it would be a pity to switch to something else, so i'm still hoping to hear back on this issue. Any update would be appreciated, even if there are no plans to fix it 🙏

@RobinMalfait
Copy link
Collaborator

Hey sorry for the late response @AnnaYuS!

We recently did a bunch of performance improvements for the Vue version of the Combobox component. One of those changes is that we delay marking an option as active if you are going to an other option in rapid succession. Can you check if this improves/fixes the issue. If not we will have to dig deeper, but checking that would be awesome.

You can try the insiders version using:

  • npm install @headlessui/vue@insiders.

@AnnaYuS
Copy link
Author

AnnaYuS commented Jul 13, 2023

Thanks for your reply @RobinMalfait! Glad to hear that you are looking into it. Tried it out, but unfortunately the problem is still there. Maybe it's worth mentioning that in Chrome it works fine, the problem is with Firefox (starting from v1.7.5), in Safari it seems to also happen in versions older than 1.7.4

@rigtigeEmil
Copy link

rigtigeEmil commented Jul 29, 2023

Is there any update on this issue, or known workarounds? I'm experiencing the same, also in Chrome.
I tried the insiders version as well, which does not resolve the issue.

The issue only appears if an item has been hovered. If nothing is hovered, then the issue disappears

@Saul-BT
Copy link

Saul-BT commented Aug 1, 2023

Describe your issue Starting from v.1.7.5 there is a problem with the scroll when virtual list is used with Combobox options. As was mentioned in this issue, the virtual lists don't work well with headless ui at the moment, but perhaps there is something that can be fixed in this case? Or maybe there is some sort of a workaround? This might have something to do with these changes For now we had to pin v1.7.4, but we'd really like to upgrade to get all the fixes and new stuff Before the upgrade to v1.7.5 the virtual lists weren't working perfectly, but they were more usable, and now scrolling is too problematic. Your feedback would be greatly appreciated pray

I can confirm that the root of the problem comes from these changes.

Warning: don't do this, I just did it to confirm that the problem really comes from that change.

I took a look at the changes @AnnaYuS commented and saw that the useTrackedPointer hook was used. Then I roughly updated the code so that the aforementioned hook does nothing, and the scroll seems to behave correctly 🥲 .


Is anyone working on this? 🥲🥲🥲

@erquhart
Copy link

erquhart commented Aug 5, 2023

This is not Vue specific, happening in React, too as of 1.7.16.

I'm also seeing this as far back as 1.6.0 of the react lib, didn't check back further than that as other things started breaking.

@RobinMalfait issues like this make the decision to exclude virtualization (#474 (comment)) challenging. Combobox simply doesn't work for large lists, so there's an argument to be made for this being a core concern - even if "support" just means a tested example implementation using an external library like @tanstack/react-virtual.

I'm working on anchoring my current team's UI work in Tailwind UI (and therefore Headless UI) and am now working through this bug as a part of that effort. Maybe worth considering how one affects the other here.

@erquhart
Copy link

erquhart commented Aug 5, 2023

Also this does seem to be relevant, there's more comments after it was closed that clarify the issue: #2490

@Saul-BT
Copy link

Saul-BT commented Aug 6, 2023

Hi, I managed to avoid most of the cases where this happens.
But in trade off for probably affecting accessibility....

<ComboboxOption
    v-for="option in list"
    v-slot="{ active }"
    :key="option.data.id"
    :value="option.data"
    :title="option.data.value"
    as="template"
    class="tw-h-9"
    >
      <li
        @focus.prevent
        @mouseenter.prevent
        @pointerenter.prevent
        @mousemove.prevent
        @pointermove.prevent
        @mouseleave.prevent
        @pointerleave.prevent
        :class="[
          active
            ? 'tw-bg-slate-100 tw-text-slate-900'
            : 'tw-text-slate-700',
          '... hover:tw-bg-slate-100 hover:tw-text-slate-900',

As you can see, I use event.preventDefault() for the events focus, mouseenter, pointerenter, mousemove, pointermove, mouseleave and pointerleave. This is a very dangerous workaround and don't work in all cases (ex. when the first option is active, and you pretend to scroll with the mouse over that option).

@RobinMalfait RobinMalfait self-assigned this Aug 11, 2023
@firstpromoter
Copy link

firstpromoter commented Aug 23, 2023

This issue is really bad. We're looking for alternative in this case, even though we're a paying customer of Tailwind UI. There's a huge performance problem with combobox, even with relatively few items which forces us to use virtual list. However, with virtual list we get this issue which we can't fix and is not something we can use going forward.

@RobinMalfait
Copy link
Collaborator

RobinMalfait commented Sep 15, 2023

Hey!

We just merged an experimental feature where we added native support for virtual lists. More info can be found in the PR: #2740

But the TL;DR is this:

  1. Remove the custom virtualization you were doing
  2. Apply the following diff:

React:

- <Combobox>
+ <Combobox virtual>
    <Combobox.Input />
    <Combobox.Options>
      {countries.map((country, idx) => (
-       <Combobox.Option key={country} value={country}>
+       <Combobox.Option key={country} value={country} order={idx}>
          {country}
        </Combobox.Option>
      ))}
    </Combobox.Options>
  </Combobox>

Vue:

- <Combobox>
+ <Combobox virtual>
    <ComboboxInput />
    <ComboboxOptions>
      <ComboboxOption 
-       v-for="country in countries"
+       v-for="(country, idx) in countries"
+       :order="idx"
        :key="country" 
        :value="country"
      >
        {country}
      </ComboboxOption>
    </ComboboxOptions>
  </Combobox>

By adding native support for virtual lists we can ensure that all the mouse and keyboard interactions work as expected, while also guaranteeing that the accessibility is on point and that using assistive technology works as expected.

I've also updated the StackBlitz link using the virtual changes: https://stackblitz.com/edit/vue-cpfspz?file=src%2Fcomponents%2FHelloWorld.vue

Please test it and open any issues if you run into them.

You can already try it using:

  • npm install @headlessui/react@insiders.
  • npm install @headlessui/vue@insiders.

@rigtigeEmil
Copy link

For me, the proposed solution looks nice, but from the StackBlitz link, the performance is an issue for me. It takes a few seconds closing/opening the dropdown.

@yakobe
Copy link

yakobe commented Sep 18, 2023

Hi @RobinMalfait . Thanks for adding a native virtual list to the combobox! 👍 . However, I am also seeing major performance problems with that stackblitz example. Is there something wrong with the example or does the virtual list not work? It takes several second to open/close the dropdown and search for values. Perhaps this issue is not ready to be closed yet?

@jord1e
Copy link

jord1e commented Sep 18, 2023

To make stackblitz crash on Firefox:

Type h
Type j
Type <backspace>
Type <backspace>
Repeat this maybe 1-3x
grafik

@senaria
Copy link

senaria commented Sep 18, 2023

To your error @jord1e it looks like the data needs some fixing. The filteredPeople need to fallback to an empty array on line 177.

let filteredPeople = computed(() => {
      return query.value === ''
        ? people
        : people.filter((person) =>
            person.name
              .toLowerCase()
              .replace(/\s+/g, '')
              .includes(query.value.toLowerCase().replace(/\s+/g, ''))
          ) ?? [];
    });

@jord1e
Copy link

jord1e commented Sep 18, 2023

@senaria Seems plausible
When you remove the “first” character (in my example h) it also lags 3 seconds before the error appears, it also appears to be nondeterministic, which is not great—even though the data is probably wrong yes.

Just commenting my observation, I use the React version of HUI.

@yakobe
Copy link

yakobe commented Sep 18, 2023

It seems that it is rendering <!----> for each of the items that are not shown for the virtual list. As you scroll up and down they appear before and after the visible list items. I am guessing it uses a v-if to render from the total list of data, which would not give any of the virtuallist performance benefits 🙁.

In order for vue to benefit from the virtual list, I think it should only loop the values that should be displayed and they should have a key to ensure they re-render when the data changes.

@RobinMalfait
Copy link
Collaborator

Hi all!

We changed the API a bit more to ensure that on even larger lists the virtualization works as expected without the initial slowdown when opening the Combobox.

The PR with more information and the new API can be found here: #2779

Some demo's can be found here (WARNING: do not try to open the Combobox on the right with more than 1000 items, or your computer might turn into a stove or a helicopter):

@AnnaYuS
Copy link
Author

AnnaYuS commented Nov 7, 2023

Thank you for your work, it's much appreciated. While testing it, I noticed a minor issue. When there's no selected option or an empty search, scrolling past the initial default option can be challenging. However, once you move the cursor within the list, it functions perfectly. Looking forward to the official release!

Screen.Recording.2023-11-07.at.17.26.32.mov

@AvdylKrasniqi
Copy link

Thank you for your work, it's much appreciated. While testing it, I noticed a minor issue. When there's no selected option or an empty search, scrolling past the initial default option can be challenging. However, once you move the cursor within the list, it functions perfectly. Looking forward to the official release!
Screen.Recording.2023-11-07.at.17.26.32.mov

I've been able to reproduce similar bug as well.
Step to reproduce:

  1. Open combobox
  2. hover the mouse into random element.
  3. Press arrow up or down,
  4. try to scroll
2023-11-11.20-44-49.mp4

@AnnaYuS
Copy link
Author

AnnaYuS commented Nov 28, 2023

@RobinMalfait Do you have any estimate on when the next release might be? It'd be a huge help for our plans. Thanks for all your hard work!

@ben-hapip
Copy link

@RobinMalfait any timeframe for when headless 2.0 will be released?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet