react-select icon indicating copy to clipboard operation
react-select copied to clipboard

Enter key submitting form when menu open but showing no options

Open jamosonic opened this issue 6 years ago • 11 comments

Within a <form onSubmit={}> form that uses an onSubmit handler and a regular old <button type="submit">, the enter key is submitting the form despite the react-select menu being open. This seems to happen when there are no options to display in the list.

image

Have created a quick demo here:

https://codesandbox.io/s/react-codesandboxer-example-i6bwn

Steps to reproduce:

  1. Type any non-existent colour in the select and ensure you are seeing the "No options" message.
  2. Hit enter, see the alert that the form has been submitted.

Is this intended behaviour?

Thanks :)

jamosonic avatar Oct 22 '19 03:10 jamosonic

My temporary solution is disable to submit the form while any menu of react-select is open.

dragonnpoulp avatar Nov 02 '19 05:11 dragonnpoulp

Hey @joshamos! You need to prevent the default keydown behaviour. You can use the onKeyDown prop to customize it.

Eg.

const keyDownHandler = e => {
  if (e.key === "Enter") e.preventDefault();
}

<Select ...otherprops onKeydown={keyDownHandler} />

Eg. codesandbox here — https://codesandbox.io/s/react-select-form-submit-jdme8

I'm closing this issue now. If you need to discuss it further pl feel free to reopen it.

flexdinesh avatar Apr 08 '20 02:04 flexdinesh

@flexdinesh I'm facing the same thing and I believe this is a real issue:

your proposed solution does prevent form submit when hitting enter with no options to choose from, but it also prevents selecting an option with the enter key when there are options to choose from, and it also prevents submission of the form by pressing the enter key when the menu is not open.

i believe the correct behaviour should be as described in this issue: #2798 - "If the input has focus, with the menu closed, pressing enter should submit a containing form." - but if the menu is open, it shouldn't.

i think this should be able to be fixed by adding e.preventDefault() in this block before the return statements: https://github.com/JedWatson/react-select/blob/397e95337f54074cf0705cb5b06ce8951be72f2a/packages/react-select/src/Select.js#L1231-L1235 so that we never propagate the enter key if the menu is open. happy to submit a PR if you would like!

rsslldnphy avatar Aug 27 '20 14:08 rsslldnphy

Greetings @rsslldnphy ,

Sorry for the long delay in getting a response to you. I am able to reproduce the described error. Would you still be interested in submitting a PR for this and perhaps a test or two if you feel comfortable?

ebonow avatar Jan 28 '21 23:01 ebonow

Did you find any solution for this?

usamamashkoor avatar May 06 '21 00:05 usamamashkoor

Hey @joshamos! You need to prevent the default keydown behaviour. You can use the onKeyDown prop to customize it.

Eg.

const keyDownHandler = e => {
  if (e.key === "Enter") e.preventDefault();
}

<Select ...otherprops onKeydown={keyDownHandler} />

Eg. codesandbox here — https://codesandbox.io/s/react-select-form-submit-jdme8

I'm closing this issue now. If you need to discuss it further pl feel free to reopen it.

For those who are trying with copy pasting: There is a typo: the prop should be onKeyDown then it works.

jackblackCH avatar Dec 10 '21 19:12 jackblackCH

Four years later and the issue is still unresolved..? :(

Having the same exact problem. Disabling enter onKeyDown is not an acceptable solution as now the user can't select options with the keyboard anymore.

Very unfortunate - this is enough to make the entire library unusable for me.

CristianCrane avatar Feb 18 '23 21:02 CristianCrane

I worked on a workaround for this problem using an AsyncCreatableSelect.

The main problem with ev.preventDefault() is you can no longer select list options using "enter" as pointed out by @CristianCrane . Because this is intuitive user behaviour I agree this is not acceptable.

Some context; the form I am working on required input to have at least 3 characters otherwise the select menu would be closed i.e. menuIsOpen={inputValue.length > 2}.

My attempted workaround involved enabling/disabled the onKeyDown handler for this form like this:

onKeyDown={canSelectOrCreateOption ? undefined : handleKeyDown}

The canSelectOrCreateOption would look like this:

// This key down handler prevents an "enter" key from submitting the form.
// However, we cannot disable "event.preventDefault" for the "enter" key
// altogether because we need it to confirm a selected option when the menu
// is open.
//
// So instead we use this key event handler only when:
//
// - the menu is closed (which happens when input is less than 3 characters).
// - no options can be selected, which occurs when:
//   - the options are loading or empty
//   - the inputValue cannot be created because it already exists
const handleKeyDown: KeyboardEventHandler = (event) => {
    if (!inputValue) {
      return;
    }

    switch (event.key) {
      case "Enter":
      case "Tab":
        setMenuIsOpen(false);
        setValue((prev) => {
          const newOptions = [...prev, createOption(inputValue)];
          return uniqBy(newOptions, "value");
        });
        setInputValue("");
        event.preventDefault();
    }
  };

  // These are all conditions described in the comment above
  const hasOptions =
    options?.filter((option) => !value.some((v) => v.value === option.value))
      ?.length !== 0;
  const inputValueAlreadyUsed = value.some((v) => v.value === inputValue);
  const canSelectOrCreateOption =
    menuIsOpen && !isLoading && (hasOptions || !inputValueAlreadyUsed);

This did not work; if typing slowly it would have the correct behaviour but when typing fast and pressing enter it will still submit the form. Most likely because the rerender would not be applied quickly enough or some other condition I missed.

I eventually gave up on this approach, even if I could get it to work using useRef or similar I simply didn't want to add this this complexity to the project.

Instead I worked around it by disabling the form submit and submit it programmatically, effectively disabling all "enter" submits on text fields in the form:

<form onSubmit={(e) => e.preventDefault}>
  ...
  <button type="button" onClick={() => /*submit programatically*/} />
</form>

For my use case this was a sufficient workaround.

nielskrijger avatar Feb 24 '23 09:02 nielskrijger

If you don't need to submit the value of the async select with the form you can set the input's form attribute to a non-existing form id: <AsyncAutocomplete form="_none" ... />

johnvankeulen avatar May 17 '23 08:05 johnvankeulen

If you don't need to submit the value of the async select with the form you can set the input's form attribute to a non-existing form id: <AsyncAutocomplete form="_none" ... />

Can confirm this works for Creatable Select as well.

Sufyan-007 avatar Jun 19 '24 09:06 Sufyan-007

Would be grateful for a solution from the library side, without workarounds.

kaeruB avatar Feb 17 '25 23:02 kaeruB

I personally do consider this a bug and agree it should be addressed in the library. The default submit action on enter keydown should not propagate up to the form when the menu is open, whether there are options populated in it or not.

I did work out a working solution that 1) preserves the correct behavior when the select is focused but the menu is closed, 2) allows using the enter key when the menu is open to select an option when the options are populated, 3) supports non-enter keys (like tab and esc) to function when the menu is open.

https://codesandbox.io/p/sandbox/jmxsg9

Keep in mind that this relies on replacing the Control subcomponent. If you are already doing that for some other customization reason, you'll need to add this behavior to that existing subcomponent replacement.

eckmLJE avatar Apr 23 '25 17:04 eckmLJE

A better workaround than calling preventDefault on the React event is to get the native event and preventDefault there. Which allows React Select to still perform selection, but prevents the native behavior of submitting the form.

const keyDownHandler = e => { if (e.key === "Enter") e.nativeEvent.preventDefault(); }

JeanSamGirard avatar Nov 26 '25 15:11 JeanSamGirard