React-select: Add option to keep incomplete input onBlur

Created on 8 Nov 2018  路  16Comments  路  Source: JedWatson/react-select

Currently, if I start typing into the field and have not yet selected anything, then I leave the field, my input gets cleared out.

It would be nice to have an option to keep the input there.

Most helpful comment

Another option would be to use the onInputChange prop and manage the value of the search input via state. You just have to prevent state updates for the actions input-blur and menu-close.

class KeepSearchOnBlurSelect extends Component {
  state = {
    inputValue: ""
  };

  handleInputChange(inputValue, action) {
    if (action.action !== "input-blur" && action.action !== "menu-close") {
      this.setState({ inputValue });
    }
  }

  render() {
    const { inputValue } = this.state;
    return (
      <Select
        inputValue={inputValue}
        defaultValue={colourOptions[0]}
        name="color"
        options={colourOptions}
        onInputChange={this.handleInputChange.bind(this)}
      />
    );
  }
}

CodeSandbox

All 16 comments

hi @agonsalves ,
not sure if this is helpful but i was trying to do this as well and i managed to keep the input on mouse blur with this:

 public handleBlur = (event) => {
      const { inputValue } = this.state;
      const { value } = this.props;

      if (!_.isEmpty(inputValue)) {
        this.setState({
          inputValue: ''
        });
        this.props.onChange([...value,createOption(inputValue)]);
        event.preventDefault();
      }

    }

and i call it:

 <CreatableSelect
            components={components}
            inputValue={inputValue}
            isClearable
            isMulti
            menuIsOpen={false}
            onChange={this.handleChange}
            onInputChange={this.handleInputChange}
            onBlur={this.handleBlur}
            onKeyDown={this.handleKeyDown}
            value={value}
            className={styles.questionInput}
            styles={questionStyles}
          />

@paigeflourin Thanks. I am not sure what createOption() does, so I am not able to replicate what you've got. Any insight?

@agonsalves ,

This is my createOption

const createOption = (label: string) => ({
label,
value: label,
});

This option used to be in react-select v1 onBlurResetsInput, but is missing in v2. The line in question is in Select.js on line 1074:

onInputBlur = (event: SyntheticFocusEvent<HTMLInputElement>) => {
    if(this.menuListRef && this.menuListRef.contains(document.activeElement)) {
      this.inputRef.focus();
      return;
    }
    if (this.props.onBlur) {
      this.props.onBlur(event);
    }
    this.onInputChange('', { action: 'input-blur' }); // <-- have an option to skip this line
    this.onMenuClose();
    this.setState({
      focusedValue: null,
      isFocused: false,
    });
  };

In react-select v1, Select.js lines 416-418, this is how it used to work:

if (this.props.onBlurResetsInput) {
    onBlurredState.inputValue = this.handleInputValueChange('');
}

I'm working on a PR to include this option.

Another option would be to use the onInputChange prop and manage the value of the search input via state. You just have to prevent state updates for the actions input-blur and menu-close.

class KeepSearchOnBlurSelect extends Component {
  state = {
    inputValue: ""
  };

  handleInputChange(inputValue, action) {
    if (action.action !== "input-blur" && action.action !== "menu-close") {
      this.setState({ inputValue });
    }
  }

  render() {
    const { inputValue } = this.state;
    return (
      <Select
        inputValue={inputValue}
        defaultValue={colourOptions[0]}
        name="color"
        options={colourOptions}
        onInputChange={this.handleInputChange.bind(this)}
      />
    );
  }
}

CodeSandbox

@Rall3n
What I don't get: In a real world example you need to save the value when it was changed.
Trouble is: In your example handleInputChange gets an inputValue of '' when a value is choosen from the list.

How would you save that?

Plus: It is not efficient to save a value to the database on every change event. This becomes especially hideous if the user wants to delete inputted text. But I have not had any luck working with the blur effect. How could the value received by handleInputChange only be saved on blur?

Nope, this is not good enough:

If you type a value and blur the field the value is saved. But if you remove the value the empty value cannot be saved: onInputChange receives a value of '' when you choose a value from a list (why???), see also https://github.com/JedWatson/react-select/issues/3440. So inputValue is set to null when you choose values from the list. And onBlur and onInputChange cannot know whether the empty value they receive comes from deleting a value in the input or choosing a value from the list.

Additionally the x symbol that you could clear values with is not shown when you type a value that is not an option.

:-(

I added a bad hack to enable users to delete typed text, see in my component: https://github.com/barbalex/apf2/blob/7c11b0b065530de3c1cee4a41e1502f13f86eed9/src/components/Projekte/Daten/Tpopmassn/Wirtspflanze.js

But I realize it is a horrible hack :-(

@barbalex If you want to save the typed value, you should consider using Creatable. There you have the possibility to either select a value from the option list or create a new value. The new value gets assigned an attribute (__isNew__) which determines it has been created by the user.

Based on your use case: IMO the value in a selection component should never be created just on input, but the user should choose if he wants to create a new value. This library respects this idea in its Creatable component, having the user do an extra selection to confirm he wants to create a new value.

@Rall3n Thanks for pointing that out.

This works nice, when the user first chooses a value from the list or creates a new one.

Let's say for example, the user chooses "Blue".

The nice thing about AsyncCreatableSelect is that even if "Blue" was created as a new value, after creating it, the user sees a x symbol with which the value can be cleared.

Unfortunately the next time the form is opened (and the AsyncCreatableSelect contains "Blue" as inputVaue), the field does not show the x symbol to clear the value any more.

And when the user clicks into the field, the dropdown contains "create Blue". Which definitely will be unexpected, as "Blue" was either choosen from the list or created before.

I am pretty sure some of my users would be confused by this behaviour. So I personally will not implement this version.

Additionally: I see where explicitly creating new values makes sense and that will be most of the time. But there are use cases where this is not necessary. In the case I am implementing now, users want to be helped when typing plant names (which can be rather long and should be correct). But the field is meant to be just a regular input field with all the freedom to enter whatever. So it is expected, the user will type anything anytime.

Long story short: I still wish handleInputChange got a relevant inputValue when a value was choosen from the list and not ''.

Unfortunately the next time the form is opened (and the AsyncCreatableSelect contains "Blue" as inputVaue), the field does not show the x symbol to clear the value any more.

If you want to show the clear icon every time, set the isClearable prop.

And when the user clicks into the field, the dropdown contains "create Blue". Which definitely will be unexpected, as "Blue" was either choosen from the list or created before.

It may be because you abstract the input to be the main value holder, which is simply wrong. The input is mainly used for focus handling and searching, not to set the value. It is obvious that the Creatable would show an option to create the value because this is not its real value, but the search text. Value management happens using the value and onChange prop.


Your use case goes way beyond what this issue addresses. For further inquiries you should go over to StackOverflow (tag react-select) and ask for help there.

@Rall3n I realize that use cases for select can be rather complicated, that react-select is not a simple tool and that I may well not have understood it correctly. Thanks for your feedback and for working on this great tool!

Another option would be to use the onInputChange prop and manage the value of the search input via state. You just have to prevent state updates for the actions input-blur and menu-close.

class KeepSearchOnBlurSelect extends Component {
  state = {
    inputValue: ""
  };

  handleInputChange(inputValue, action) {
    if (action.action !== "input-blur" && action.action !== "menu-close") {
      this.setState({ inputValue });
    }
  }

  render() {
    const { inputValue } = this.state;
    return (
      <Select
        inputValue={inputValue}
        defaultValue={colourOptions[0]}
        name="color"
        options={colourOptions}
        onInputChange={this.handleInputChange.bind(this)}
      />
    );
  }
}

CodeSandbox

It has some problems in AsyncSelect

Working solution with AsyncSelect:

  const onInputChange = (query, { action }) => {
    if (action === 'input-change') {
      setInputValue(query);
      return query;
    }
    return inputValue;
  };

Hello -

In an effort to sustain the react-select project going forward, we're closing old issues.

We understand this might be inconvenient but in the best interest of supporting the broader community we have to direct our efforts towards the current major version.

If you aren't using the latest version of react-select please consider upgrading to see if it resolves any issues you're having.

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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

juliensnz picture juliensnz  路  3Comments

steida picture steida  路  3Comments

coder-guy22296 picture coder-guy22296  路  3Comments

geraldfullam picture geraldfullam  路  3Comments

mjuopperi picture mjuopperi  路  3Comments