JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.49k stars 4.12k forks source link

Selected option isn't focused when opening menu #5729

Open samuelstecher opened 1 year ago

samuelstecher commented 1 year ago

Hey :)

Explanation

I like to report the a bug but for this, I need to explain the expected behaviour first: When an option is selected, and one opens the menu I expect the selected option to appear selected, be in view and focused so up/down arrows work immediately.

This works in principle, however I found a caveat that I consider to be a bug, or at least, I haven't found a way to fix it in my code: I use { label: string; value: string } objects as options for my select component. When the value (aka the selected option) of the select is one of the option objects in the options array (aka value={options[x]}) it works as expected. I'm guessing because value === options[x]. If I were to reconstruct the value object so the object references don't match any of the options but the contents are the same, it will break the expected behaviour and always focus the first option.

Reproduction

const options = new Array(20)
  .fill(null)
  .map((_, i) => ({ value: `${i + 1}`, label: `Option ${i + 1}` }));

// this will open the menu correctly
<Select options={options} value={options[14]} />

// this will reproduce the bug
<Select options={options} value={{ label: 'Option 15', value: '15' }} />

I also created a Codesandbox for reproduction.

Attempts to fix it

I tried to play around with getOptionValue and isOptionSelected properties but I didn't get it to work. Also menuShouldScrollIntoView didn't do anything. I'm kinda out of ideas on what to try.

labkey-nicka commented 1 year ago

This is intended behavior. The key to getting your option-based value scenario to work is you need to reuse the same instance of the "option" (as you see when you use option[14]) as react-select does not attempt to do any form of deep equivalency.

const newOption = { label: 'Option 15', value: '15' };

// This is false. They are not the same instance.
newOption === options[14]

Note, if you want this to a be an uncontrolled input then use defaultValue to supply that initial value then you don't need to reflect the value back into the input.

samuelstecher commented 12 months ago

Hey @labkey-nicka thanks for your response. I think this very weird behaviour. It also feels kinda sketchy to soly rely on the reference of the object. As a user of this library, I at least expected to be able to influence this behaviour by providing an isOptionSelected or some other prop. Would that be a reasonable feature request?

samuelstecher commented 11 months ago

I have another usecase that is interesting in this context: I'm trying to build a TimePicker. It's basically a dropdown with 15-minute slots that a user can choose from (12:00am, 12:15am, 12:30am, 12:45am .... 11:00pm, 11:15pm ....). Now, if nothing is selected (yet), the initially focused option will always be the first. This is a bit inconvenient for this usecase UX wise because the likelyhood of somebody scheduling something at 12am is far less than scheduling something at like 8am so I'd rather start at an option in the middle so they have less way to go to the time they want to schedule at. But currently there is no way to influcence this behaviour in react-select. Because the initial focus is either at the selected option (given it finds it's reference) or at the top. How would you go about this?

RajNandigalla commented 3 months ago

@samuelstecher did you find any fix for this, facing same issue