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 should navigate to first element when pressing arrow down #2992

Open
ericbf opened this issue Feb 16, 2024 Discussed in #1851 · 3 comments
Open

Combobox should navigate to first element when pressing arrow down #2992

ericbf opened this issue Feb 16, 2024 Discussed in #1851 · 3 comments

Comments

@ericbf
Copy link

ericbf commented Feb 16, 2024

Discussed in #1851

Originally posted by **DanBoghean** September 14, 2022
The current behavior of the headlessui combobox seems to be that the selected value is set to active (gray background in a styled option for example) whenever the options dialog is open. This can change if a user hovers over different options. If a user starts typing into the input box (without hovering over other options), the selected option stays as the active value. Is it possible to change the active value to the first element in the options list if a user is typing into the input?

Follow-up posted by **ericbf** October 19, 2023
This is exactly what I’m looking for as well. We are using a fairly long list of options, so when the user types, the selected item could be pretty far down the list (below the fold). When the user types something and hits the down arrow to navigate the options, the active item starts from the selected item, jumping the view way down in a very unexpected manner.

To go along with, or support, this, is there any way to manually set the active element? Or to automatically set the active element to the first item in the list whenever the options change, _regardless of what is selected_?

Issue details

The current behavior feels 100% like a bug for users. To them, they are typing in some text in the combobox, want to navigate down to the best match (the first item in the list), when all of a sudden the list jumps way down and now their matched result is completely lost and no longer visible.

@ericbf ericbf changed the title Combobox should make first element "active" when typing Combobox should navigate to first element when pressing arrow down Feb 16, 2024
@eddking
Copy link

eddking commented Feb 19, 2024

I have posted a very hacky workaround in the discussion thread. #1851

This issue makes the combobox almost unusable as a command palette (even though tailwindui uses this component extensively in those examples). As you search for an item, I would expect items to be re-ordered and maybe new ones appear, If the active element cant be changed to the top result, then you have to manually select the correct one by click or tapping the arrows, which vastly reduces the usefulness of searching.
See the behaviour of alfred / spotlight

@ericbf
Copy link
Author

ericbf commented Feb 23, 2024

My current workaround is to not render the selected item as a Combobox.Option at all, but rather just render it as a button with role "option" and "aria-selected="false". The side effect is that you can’t arrow to the selected item at all, but I think that’s probably fine as the user wouldn’t really benefit from arrowing to the selected item. Closing the combobox with esc would be essentially selecting the selected item again. Something like this:

<OriginalCombobox.Options>
	{filteredOptions.length === 0 && query !== "" ? (
		<div>
			No matches…
		</div>
	) : (
		filteredOptions.map((option, index) =>
			value === option /* Or your comparison */ ? (
				<button
					key={keyFor(option, index)}
					className="selected-styles"
					tabIndex={-1}
					onClick={() => {
						onChange?.(option)
						comboboxButton.current?.click()
					}}
					role="option"
					aria-selected="false"
				>
					{display(option)}
				</button>
			) : (
				<OriginalCombobox.Option
					key={keyFor(option, index)}
					className={({ active }) =>
						twJoin(
							"base-styles",
							active && "active-styles"
						)
					}
					value={option}
				>
					{display(option)}
				</OriginalCombobox.Option>
			)
		)
	)}
</OriginalCombobox.Options>

Again, this is a workaround. Better would be the issue be fixed in the library itself.

@eddking
Copy link

eddking commented Feb 24, 2024

@ericbf im not sure if this is helpful for you && I've not fully tested this solution yet, but I've had some success by passing the by option and implementing a custom comparator, then embellishing the results with the query that produced them so results from different queries are not treated as the same option. its certainly not the most obvious way to control the focus state, but less hacky than my previously proposed solution

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

2 participants