react: Clear button on iOS date input does not return correct event value

Bug For iOS only. When pressing clear on a date input, the onChange event is fired but event.target.value is showing the original value rather than an empty string.

What is the current behavior? On Chrome and Android, when the clear button is pressed the onChange event has a value of ''. On iOS when the clear button is pressed the onChange event has a value of previousValue.

Demo https://output.jsbin.com/zojuteloto/5/ Try on Chrome/Android. Then on iOS.

What is the expected behavior? Value should be returned an an empty string.

Versions Affects React 15+ & iOS 10. Unsure of previous versions.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 4
  • Comments: 20 (9 by maintainers)

Commits related to this issue

Most upvoted comments

The workarounds listed so far didn’t work for me. The following worked perfectly though on iOS 11.2.2, no ref needed -

onInput(e) {
    const target = e.nativeEvent.target;
    function iosClearDefault() { target.defaultValue = ''; }
    window.setTimeout(iosClearDefault, 0);
  }

Here is another solution to this issue in case someone needs it.

iosDateInput

https://codepen.io/joseplatas/pen/yWQYeq

class App extends React.Component{
  state = {
    value: "2011-11-11"
  }

  inputRef = React.createRef();
  
  componentDidMount(){
    /*
    necessary if value is being set in mount, 
    otherwise the clear won't work on the first click
    */
    this.inputRef.current.defaultValue = "";
  }

  handleOnChange = (event)=>{
    this.setState({
      value: event.target.value
    });
    
    /*
    defaultValue seems to reset every time on the handleChange call,
    we need to set defaultValue again as it is change.

    setTimeout is required for this to work, it needs a small delay
    otherwise defaultValue gets unset
    */
    const target = event.target; 
    setTimeout(()=>{
      target.defaultValue = "";
    }, 100);
  }
  
	render(){
    return(
      <div>
        <input 
          ref={this.inputRef}
          type="date" 
          value={this.state.value} 
          onChange={this.handleOnChange}
          /*
          NOTE: don't set defaultValue here because it will create a warning
          React will warn you that:
          Input elements must be either controlled or uncontrolled (specify               either the value prop, or the defaultValue prop, but not both).
          */
          //defaultValue=""
          />
      </div>
    )
  }
}

I’m still encountering this. Tapping on clear does not clear the field, nor restore it to its defaultValue.

Took a quick pass using the core mechanic behind inputValueTracking: ~~http://codepen.io/nhunzaker/pen/dNqvyM~~

Seems to work fine. I’ll work my way out from there.

☝️ Sorry, bit of user error… Going to keep digging.

Purely speculative, but I wonder if clear is restoring the input to its defaultValue, which is stored under the value attribute on controlled fields, much like form.reset() (which React controlled inputs don’t support).

Happy to triage this, @aweary.

Hitting Clear will indeed revert to the defaultValue DOM prop (representing the HTML attribute value) which works as expected for uncontrolled inputs. For controlled inputs, as React will update both value and defaultValue DOM props to the new value on every change, hitting Clear will have no noticeable effect. Setting the defaultValue DOM prop to the empty string manually after each change fixes this.

class DateInput extends React.Component {
  componentDidUpdate(prevProps) {
    if (prevProps.value !== this.props.value) {
      this.refs.input.defaultValue = "";
    }
  }

  render() {
    return <input ref="input" type="date" value={this.props.value} />;
  }
}

I was experimenting with the solution of @joseplatas above for a while, but couldn’t get the refs part working. Then I figured that making Clear work on first click can be done if I can clear defaultValue at the time of focusing the input, so attaching a callback to onFocus was all I needed.

return (
  <input
    type="date"
    value={this.state.value}
    onChange={this.handleOnChange}
    onFocus={(event) => event.nativeEvent.target.defaultValue = ""}
  />
);

Without React: http://codepen.io/nhunzaker/pen/VPGPzw

Seems to pick it up no problem. iOS 10 7+ emulator: ios-clear