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 items get wrong keyboard navigation order after being reordered #840

Open
avinashbot opened this issue Sep 15, 2021 · 5 comments
Open

Comments

@avinashbot
Copy link

🐛 Bug report

Current Behavior

When combobox list items are reordered, their keyboard navigation order doesn't seem to change. So if you use arrow keys to traverse through the list after a reorder, it jumps around the list instead of to the next item.

Expected behavior

When I press down, only the next immediate option should be selected.

Reproducible example

Example of a list of countries that are re-ordered as you type:
https://codesandbox.io/s/beautiful-panka-8ow2p?file=/src/App.js

  1. Type in any character. The matches are reordered so that countries that start with the letter are presented first.
  2. Now press down to traverse the list. As you traverse, you occasionally start jumping to random elements in the list.

Suggested solution(s)

I'm not sure why it's happening, but I'm guessing it has something to do with @reach/descendants. It seems like it's the same problem as in #827, but the fix in the CR doesn't help in my case.

Additional context

n/a

Your environment

Software Name(s) Version
Reach Package @reach/combobox ^0.16.1
React ^17.0.2
Browser Firefox, Chrome 92.0, 93.0.4577.82
Assistive tech None
Node 16.6.2
npm/yarn npm 7.20.3
Operating System Ubuntu 21.04
@phacks
Copy link

phacks commented Sep 27, 2021

Hey! Jumping in because I’ve had a similar issue, and found an odd fix to it. The following change:

<ComboboxList>
  {matches.map((match) => (
+    <div>
        <ComboboxOption key={match} value={match} />
+    </div>
  ))}
</ComboboxList>

appears to fix the keyboard navigation issues you see in the sandbox. I have no idea why that is, or whether the extra div is having a negative impact on accessibility, or if something other than a div would also fix this—but anyway, thought I’d share this here in the hopes it helps find a proper fix.

@avinashbot
Copy link
Author

Hi! I also found an alternative fix to this last night and forgot to mention it here. Thanks for the reminder! Mine looks like this:

<ComboboxList>
  {options.map((option, i) => (
    <ComboboxOption key={`${i}-${option.value}`} value={option.value} />
  ))}
</ComboboxList>

The trick is the use of the array index in the key. I think both of our hacks work by forcing the library to treat the child as a new element each time. I combine the value with an index to make sure every reordering is treated by React as a new element, and you wrap your option with a key-less div to do the same.

In my case, eslint-plugin-react doesn't let you get away with not putting a key in an iterated value, which is why I went with a new key each time.

@lukasvice
Copy link

Hi, I got the same problem. I solved it by explicitly setting the internal index:

<ComboboxList>
  {options.map((option, i) => (
    <ComboboxOption index={i} key={option.value} value={option.value} />
  ))}
</ComboboxList>

@jordan-paz
Copy link

Hi, I got the same problem. I solved it by explicitly setting the internal index:

<ComboboxList>
  {options.map((option, i) => (
    <ComboboxOption index={i} key={option.value} value={option.value} />
  ))}
</ComboboxList>

This worked for me, thank you!

@tometo-dev
Copy link

Hi, I got the same problem. I solved it by explicitly setting the internal index:

<ComboboxList>
  {options.map((option, i) => (
    <ComboboxOption index={i} key={option.value} value={option.value} />
  ))}
</ComboboxList>

Thank you @lukasvice. This worked for me.

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

No branches or pull requests

5 participants