mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.87k stars 32.26k forks source link

Why TextField's input label still shrinks when it blurs? #10979

Closed xiechao06 closed 6 years ago

xiechao06 commented 6 years ago

I want to implement a component that contains a TextField, when it gains focus, a dialog will open, in order to close this dialog, I have to blur the input immediately after it gains focus (otherwise input always gains focus, see https://codesandbox.io/s/oxq0x6zz9q for this behavior). But at this time, input label still shrinks, even no value is provided. That doesn't make this component unfunctional, but seems very strange.

Expected Behavior

when TextField blurs and has no value, InputLabel should not shrink

Current Behavior

Steps to Reproduce (for bugs)

https://codesandbox.io/s/vm705x7wvy

  1. click TextField "foo"
  2. click the dropback of dialog
  3. TextField "foo" still shrinks

Context

Your Environment

Tech Version
Material-UI 1.0.0-beta41
React 16.2.0
browser ubuntu 16.04 chrome Version 63.0.3239.84 (Official Build) (64-bit)
etc
lazee commented 6 years ago

I haven't look into the details of your component, but could you explain what you are trying to achieve? If you need a modifiable text field AND a way for a user to select the data for the field in an advanced dialog box, then I suggest adding a button next to the field ("Select" or something). Else the user will not be able to edit the text manually afterwards, as the dialog keeps popping up.

oliviertassinari commented 6 years ago

@xiechao06 I believe it's an event propagation issue with React. In your example, the events fire this way:

1. Input onFocus
2. Input onBlur
3. FormControl onBlur
4. FormControl onFocus

You can get around the issue by one of the two approaches:

Wait for the next event loop

        <TextField
          onFocus={() => {
            // force blurring input, otherwise input always get focus
            setTimeout(() => {
              this._input.blur();
              this.setState({ dialogVisible: true });
            })
          }}
1. Input onFocus
2. Input onBlur
3. FormControl onFocus
4. FormControl onBlur

Blur on the FormControl

        <TextField
          component={props => (
            <div
              {...props}
              onFocus={() => {
                this._input.blur();
                // this.setState({ dialogVisible: true });
              }}
            />
          )}
1. Input onFocus
2. Input onBlur
3. FormControl onBlur