reactjsreact-select

React-select wrong focus


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.


Solution

  • 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:

    Keep:

    closeMenuOnSelect={false}
    blurInputOnSelect={false}