Skip to content

[v2] Custom Components, closeMenuOnSelect=false click outside do not close menu #2810

Closed

Description

@jakub-chatrny

While implementing custom menu with option closeMenuOnSelect=false click outside do not close menu. Issue is probably cause lose of input focus.

  • Open menu and click outside, menu close as expected
  • Open menu, clear all items and click outside, menu close as expected
  • Open menu, select option and click outside menu is still open
  • Open menu, clear any option and click outside menu is still open
const props = {
           ...
           components: {
                Menu: ({options: renderedOptions, selectOption, selectProps, innerProps}) => (
                    <DropdownMenu className={`${classNamePrefix}__menu`} {...innerProps}>
                        {
                            renderedOptions && renderedOptions.length > 0
                                ? (renderedOptions.map((option) => (
                                    <DropdownItem
                                        key={option[VALUE_KEY]}
                                        tag="div"
                                        onClick={() => selectOption(option)}
                                        className={classnames(`${classNamePrefix}__menu-option`, {
                                            [`${classNamePrefix}__menu-option_is-selected`]: selectProps.value && (
                                                Array.isArray(selectProps.value)
                                                    ? selectProps.value.some((selectedValue) => selectedValue[VALUE_KEY] === option[VALUE_KEY])
                                                    : selectProps.value[VALUE_KEY] === option[VALUE_KEY]),
                                        })}
                                        role="option"
                                    >
                                        {option.name}
                                    </DropdownItem>
                                )))
                                : <span className={classnames(`${classNamePrefix}__no-options`)}>{msg.noOptions}</span>
                        }
                    </DropdownMenu>
                ),
                ValueContainer: ({children, ...restValueContainerProps}) => (
                    <DropdownToggle className={`${classNamePrefix}__flip-toggle`} tag="div">
                        <components.ValueContainer {...restValueContainerProps}>
                            {children}
                        </components.ValueContainer>
                    </DropdownToggle>
                ),
                MultiValueContainer: ({children, ...restValueContainerProps}) => (
                    <DropdownToggle className={`${classNamePrefix}__flip-toggle`} tag="div">
                        <components.MultiValueContainer {...restValueContainerProps}>
                            {children}
                        </components.MultiValueContainer>
                    </DropdownToggle>
                ),
                IndicatorSeparator: () => <span />,
            }
}

note: Im using reactstrap coponents becasuse their handle menu floping when its needed

Activity

  1. j-funk commented on Jan 18, 2019

    @j-funk

    I think this is related to #2597

  2. clickblipclick commented on Dec 26, 2019

    @clickblipclick

    Here's a minimal reproduction of this issue:
    https://codesandbox.io/s/ecstatic-chatelet-nupqk?fontsize=14&hidenavigation=1&theme=dark

    It seems to be the case that using the provided ValueContainer component along with closeMenuOnSelect={false} causes the menu to not close on click outside. This is also an issue with V3.

  3. clickblipclick commented on Dec 26, 2019

    @clickblipclick

    And I think I just figured out why. You can't define your replacement component directly on the components prop object like this:

    <Select
      options={options}
      value={selectValue}
      closeMenuOnSelect={false}
      onChange={value => setSelectValue(value)}
      components={{
        ValueContainer: props => <components.ValueContainer {...props} />
      }}
    />

    You have to define the custom component elsewhere outside the render like so:

    const CustomValueContainer: React.FC = props => (
      <components.ValueContainer {...props} />
    );
    
    const App = () => {
      const [selectValue, setSelectValue] = useState();
      return (
        <div className="App">
          <Select
            options={options}
            value={selectValue}
            closeMenuOnSelect={false}
            onChange={value => setSelectValue(value)}
            components={{
              ValueContainer: CustomValueContainer,
            }}
          />
        </div>
      );
    };

    Why? I assume because there is some side-effect event listener being added, on recreating the component on every render causes that not to work. (Just a guess).

  4. todesstoss commented on Feb 24, 2020

    @todesstoss

    Faced the same issue.

    You have to define the custom component elsewhere outside the render like so:

    In this case it's no possible to provide custom props to this custom component

    UPD:

    for someone else facing same issue, custom props can be passed on Select element and accessed via props.selectProps

  5. deniswvieira commented on Mar 11, 2020

    @deniswvieira

    Wow

    You have to define the custom component elsewhere outside the render like so:

    Nice catch!

    Anyway it would be nice not to have caution defining components outside the scope.

  6. tswes commented on Mar 18, 2020

    @tswes

    Faced the same issue.

    You have to define the custom component elsewhere outside the render like so:

    In this case it's no possible to provide custom props to this custom component

    UPD:

    for someone else facing same issue, custom props can be passed on Select element and accessed via props.selectProps

    @todesstoss thank you for this; solved the issue for me.

  7. bladey commented on Jun 3, 2020

    @bladey
    Contributor

    Hi all,

    In an effort to sustain the react-select project going forward, we're closing issues that appear to have been resolved via community comments or issues that are now redundant based on their age.

    However, if you feel this issue is still relevant and you'd like us to review it - please leave a comment and we'll do our best to get back to you, and we'll re-open it if necessary.

  8. manisha-seclogic commented on Jul 15, 2021

    @manisha-seclogic

    Here's a minimal reproduction of this issue:
    https://codesandbox.io/s/ecstatic-chatelet-nupqk?fontsize=14&hidenavigation=1&theme=dark

    It seems to be the case that using the provided ValueContainer component along with closeMenuOnSelect={false} causes the menu to not close on click outside. This is also an issue with V3.

    so what is the solution if we want to keep both
    please help

  9. achorein commented on Jun 3, 2022

    @achorein

    After several tries, i came to a hacking solution :

    • reinject missing input (last children of original ValueContainer
    • force focus on input when value change (menu stay open on selection)

    (no need of external component)

    const App = () => {
      const [selectValue, setSelectValue] = useState();
      const ref = useRef(null);
      return (
        <Select
          ref={ref}
          options={options}
          value={selectValue}
          closeMenuOnSelect={false}
          onChange={value => {
            setSelectValue(value);
            // focus on nextTick (when an option is selected)
            setTimeout(() => ref.current?.focus());
          }}
          components={{
            ValueContainer: props => (
              <components.ValueContainer {...props}>
                Custom Label
                {_.last(React.Children.toArray(props.children))}
              </components.ValueContainer>
            );
          }}
        />
      )
    }
  10. faizantroon commented on Aug 4, 2023

    @faizantroon

    Today i have come across with this issue and i resolved it by moving my custom components outside of React functional component, Basically you can't define functional component within another functional component because it cause re renders and it will not close the dropdown

  11. nynevi commented on Jan 5, 2024

    @nynevi

    for people who is still scratching their heads around why it does not work after extracting components to be outside our functional component's return or class component's render method; wrap the components in a useMemo rather than extracting it to be outside. an example:

    const _components = useMemo(() => {
            return {
                ...props.components,
                Input: (props: any) => SelectInput(props, inputClassname),
                Control: (props: any) => SelectControl(props, controlClassname),
                DropdownIndicator: SelectDropdownIndicator,
                ValueContainer: (props: any) =>
                    SelectValueContainer(props, valueClassname),
                Menu: (props: MenuProps<any, any>) => (
                    <SelectMenu
                        {...props}
                        onOpenMenu={selectAutofocusInputBackWhenMenuOpens}
                    >
                        {props.children}
                    </SelectMenu>
                ),
                MenuList: (props: MenuListProps) => (
                    <SelectMenuList {...props}>{props.children}</SelectMenuList>
                ),
                Option: SelectOption,
                SingleValue: SelectSingleValue,
            } as any
        }, [props.components, inputClassname, controlClassname, valueClassname])
    

    please note that if dependencies of the useMemo change, you'll still run into the same issue so the dependencies should not contain props that change depending on the menu (or the input in my case)

  12. danielgamboar commented on Jan 17, 2024

    @danielgamboar

    @faizantroon

    Today i have come across with this issue and i resolved it by moving my custom components outside of React functional component, Basically you can't define functional component within another functional component because it cause re renders and it will not close the dropdown

    MAGIC!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions