I have the following react-select select component:
<Select
className={styles.multiselect}
components={{
Option: OptionBlock,
}}
isMulti
closeMenuOnSelect={false}
hideSelectedOptions={false}
onChange={handleChange}
value={selectedOptions}
blurInputOnSelect={false}
onMenuOpen={() => setIsOpen(true)}
onMenuClose={() => setIsOpen(false)}
placeholder="Select one or more topics of interest"
options={options}
styles={multiselectStyles}
/>
and here's my custom option component:
import { components, type OptionProps } from 'react-select';
import type { ColorOption } from '../data/color-option';
export function OptionBlock({ children, ...props }: OptionProps<ColorOption, true>) {
const { isSelected, isMulti, data } = props;
return (
<components.Option {...props}>
{isMulti ? (
<>
<input type="checkbox" checked={isSelected} value={data.value} onChange={() => {}} />
<label>{data.label}</label>
</>
) : (
children
)}
</components.Option>
);
}
I have two questions and would really appreciate it if someone could nudge me in the right direction.
The first problem is that when I open the select dropdown, the focus is on the last option that is visible in the current scroll context. I want the focus to be on the first option by default. By playing with it, I am also left with the impression that the focus is put on a random option, when selecting different ones, so I am not really sure I understand what's going on.
I am also not sure I understand why I need the blurInputOnSelect={false}
when I already have closeMenuOnSelect={false}
, but if I don't have it, the menu closes on every option selection.
The version I am using is 5.10.1 so all issues I found opened on github should already be fixed in that version.
Any help would be appreciated.
Problem 1: Focus defaults to the last visible option instead of the first
When the dropdown menu opens, react-select
sets focus to:
However, with isMulti
and closeMenuOnSelect={false}
, selecting options doesn't reset the internal menuScrollToFocusedOption
behavior — it tries to preserve the scroll and focus context, even across multiple selections.
Solution: Force focus to the first option on menu open
Use the menuIsOpen
state together with a menuScrollToFirstOption
trick like this:
import { useEffect, useState } from 'react';
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [selectRef, setSelectRef] = useState<any>(null);
useEffect(() => {
if (menuIsOpen && selectRef) {
// Force focus on the first option
const listbox = document.querySelector('[id$="-listbox"]');
if (listbox && listbox.firstChild) {
(listbox.firstChild as HTMLElement).scrollIntoView({ block: 'nearest' });
}
}
}, [menuIsOpen]);
And update your :
<Select
ref={setSelectRef}
menuIsOpen={menuIsOpen}
onMenuOpen={() => setMenuIsOpen(true)}
onMenuClose={() => setMenuIsOpen(false)}
...
/>
Problem 2: Why is blurInputOnSelect={false}
needed even with closeMenuOnSelect={false}
?
This is due to internal focus handling in react-select
:
By default, blurInputOnSelect
is true
, which blurs the input after
selection, and blur
triggers onMenuClose
.
So even with closeMenuOnSelect={false}
, a blur can still close the
menu.
Keep:
closeMenuOnSelect={false}
blurInputOnSelect={false}