mui / material-ui

Material UI: Ready-to-use foundational React components, free forever. It includes Material UI, which implements Google's Material Design.
https://mui.com/material-ui/
MIT License
91.86k stars 31.57k forks source link

[TextField] Form autofill doesn't update floating label text on textfield #718

Closed illogikal closed 6 years ago

illogikal commented 8 years ago

When you use chrome to autofill text fields, the floating label text doesn't animate and show at all (as of 0.8.0)

illogikal commented 8 years ago

This is probably a good place to start...

shaurya947 commented 8 years ago

@illogikal could you post of gif that?

mbrookes commented 8 years ago

Here you go:

image

The yellow highlight indicates the fields have been autofilled. As you can see, the password is filled, but the label is still in place.

newoga commented 8 years ago

Mm, that's interesting. @mbrookes Do you know if it's for all input types or just password inputs?

mbrookes commented 8 years ago

Not sure - I tried swapping the order of address and password, but autofill didn't fire, either to fill in a known user/password, or to save a new one. I'll have to figure out how best to test other fields.

newoga commented 8 years ago

Okay, I plan on revisiting refactoring some of the TextField stuff in the near future. I'll try to experiment a bit too. Let me know if you notice anything else.

simensen commented 8 years ago

Hello! We're running into this issue. Is there anything we can do locally to try and experiment w/ some potential fixes for this? Or is it going to have to wait on a refactor?

simensen commented 8 years ago

We have the exact problem with the password field listed above. In addition to that we have a similar problem with a plain TextField. We have hint text set which goes away if you type values in. However, if we set a value when the page renders (deep link) the hint text is still visible behind the actual value. Is this likely the same issue or would that be something separate?

image

oliviertassinari commented 8 years ago

Is this likely the same issue or would that be something separate?

That looks like a different issue.

antoinerousseau commented 8 years ago

inspiration for a fix: https://github.com/appsforartists/gravel/blob/master/src/components/Input.jsx#L208

antoinerousseau commented 8 years ago

that code could be added to onChange to update a state.isAutofilled

liesislukas commented 8 years ago

Chrome Version 49.0.2623.87 (64-bit) OS X El Capitan

image

if any key is pressed or mouse clicked - it floats correctly, but initial load is broken.

buunguyen commented 8 years ago

Exact same problem:

s

cezarsmpio commented 8 years ago

Any idea, guys?

wojtkowiak commented 8 years ago

Experiencing the same issue.

kand617 commented 8 years ago

Is there a way to disable autofill that works with MUI?

mbrookes commented 8 years ago

@kand617

Simply create a couple of fields and make them hidden with "display:none". Example:

Then put your real fields underneath.

http://stackoverflow.com/questions/15738259/disabling-chrome-autofill

devdlabs commented 7 years ago

any solution to fire onChange event ?

antoinerousseau commented 7 years ago

@devdlabs https://github.com/callemall/material-ui/pull/3372/files

devdlabs commented 7 years ago

@antoinerousseau Is this going to be merged in master?

mbrookes commented 7 years ago

@devdlabs https://github.com/callemall/material-ui/pull/3372#issuecomment-191523369

cacieprins commented 7 years ago

This might be a similar issue (same root cause, different manifestation?)

I'm not seeing the animation issues as mentioned, but the height of the TextField container does not take into account the top margin on the input. This results in the TextField extending 14px below the container. It's a fairly straightforward workaround, but I'm only seeing it with autocomplete:

screen shot 2016-06-22 at 9 58 04 am screen shot 2016-06-22 at 9 58 16 am screen shot 2016-06-22 at 9 58 27 am screen shot 2016-06-22 at 9 58 34 am

nathanmarks commented 7 years ago

This will be fixed soon ;)

image

antoinerousseau commented 7 years ago

nice @nathanmarks, thanks!!

and did you find a hack to update the floating label when chrome autofills without clicking the page, too?

adamtal3 commented 7 years ago

This is still a pretty painful issue.

I tried using vanilla-autofill-event which just didn't work.

I'm using redux-form (like many others) and I came around with an ugly workaround (just for my login form, I don't care about other forms). I tested it only in chrome so use it under consideration.

When I added an hidden username and password fields chrome ignored the entire form (unless hiding them with display:none which chrome didn't care about).

So I used 4 ( :disappointed: ) extra fields. 2 to make chrome ignore my form (autocomplete=off didn't work) and 2 more in a different fake form to make chrome fill, than in componentDidMount I added a timeout that copied the values from the fake fields to the real ones using redux-form change event:

class Login extends Component {
  // This was tested under chrome only. It's ugly, but it works. Code was modified a bit for simplicity so it might not work out of the box.

  componentDidMount() {
    // Fix chrome auto-fill
    setTimeout(() => {
      const { change, dispatch }= this.props;
      if (this.refs.usernameAutoFill.value && ! this.refs.username.value) {
        dispatch(change('username', this.refs.usernameAutoFill.value));
      }
      if (this.refs.passwordAutoFill.value && !this.refs.password.value) {
        dispatch(change('password', this.refs.passwordAutoFill.value));
      }
    }, 500);
  }

  render() {
    const styles = {
      autofill: {
        height: 0,
        width: '1px',
        position: 'absolute',
        left: 0,
        top: 0
      }
    };

    return (
      <div>
        <form style={styles.autofill}>
          <input type="text" ref="usernameAutoFill" name="usernameAutoFill" />
          <input type="password" ref="passwordAutoFill" name="passwordAutoFill" />
        </form>
        <form autocomplete="off">
          <div style={styles.autofill}><input type="text" name="fakeusername" /><input type="password" name="fakepassword" /></div>
          <Field name="username" component={() => <TextField ref="username" name="username" floatingLabelText="Username" />}/>
          <Field name="password" component={() => <TextField ref="password" name="password" type="password" floatingLabelText="Password" />}/>
          <RaisedButton primary={true} label="Login" type="submit"/>
        </form>
      </div>
    )
  }
}
export default {
  Form: reduxForm({
    form: 'Login'
  })(Login)
}

I've modified the code for simplicity so use it just for reference.

justinko commented 7 years ago

@adamtal3 it's autoComplete="off"

adamtal3 commented 7 years ago

@justinko It doesn't really matter. If you use autoComplete react will change it to autocomplete. You can see I used a string value ("off") and not a js value ({'off'}).

If you're referring to React standards and consistency than I agree, but I don't think it's a big deal.

whtang906 commented 7 years ago

This is my solution.

First, I checked if the username is autofilled when the component did mount. If yes, I would update the state of the password field. Once the hasValue turned to true, the floating label will be updated.

componentDidMount() {
    setTimeout(() => {
        if(this.refs.username.getValue()) {
            this.refs.password.setState({...this.refs.password.state, hasValue: true})
        }
    }, 100)
}

Hope this helps. :)

wisie2210 commented 7 years ago

i found a way to update the floating label when it was auto filled by the browser. `

setTimeout(function () { var autofilled = document.querySelectorAll('input#password:-webkit-autofill'); if (autofilled) { $("input[type=password]").parent().addClass("is-dirty"); } }, 500); ` this should be inside your document ready at the end. class "is-dirty" is the class that triggers your floating label.

ErrorPro commented 7 years ago

I'm using redux-form with react-ui. The solution for me is place the fake input right after the needed input.

  <TextField
     {...password}
     type="password"
     placeholder={formatMessage(messages.loginPasswordPlaceholder)}
     disabled={submitting}
   />
   <Icon name="password" className={theme.icon}/>
   <input className={theme.hiddenInput} type="password" />
mbrookes commented 7 years ago

Should be hopefully fixed by React 16: https://github.com/facebook/react/issues/7211#issuecomment-266774957

brunocarneiro commented 6 years ago

Same problem happened to me when I updated from 0.17.1 to 0.18.1

yhaskell commented 6 years ago

Fix that worked for me:

class FixedTextField extends Component {
    constructor() { 
       super()
       this.state = { value: '' } }
    }
    textfield = null

    componentDidMount() {
        requestAnimationFrame(() => {
            this.setState({ value: this.textfield.getInputNode().value })
        })
    }
    render() {
       return <TextField {...this.props} value={this.state.value} />
    }
}
mbrookes commented 6 years ago

The back port of the fix has just been released in React 15.6.0. Anyone in a position to test whether it resolves this issue?

[FYI: The "me too" post above will be deleted - please use the voting buttons rather than pulse the discussion.].

Stupidism commented 6 years ago

@mbrookes Not fixed as I tested.

mbrookes commented 6 years ago

@Stupidism Details?

Stupidism commented 6 years ago

Just like the one you posted 2 years ago. https://github.com/callemall/material-ui/issues/718#issuecomment-167445748

mbrookes commented 6 years ago

@Stupidism What version of Material-UI, what version of React, what browser / version?

Stupidism commented 6 years ago
  "name": "material-ui",
  "version": "0.18.3",
  "name": "react",
  "version": "15.6.0",
Google Chrome   59.0.3071.86 (Official Build) (64-bit)
OS  Linux
JavaScript  V8 5.9.211.31

image

mbrookes commented 6 years ago

:man_shrugging: In that case @whtang906's workaround seems to be the best option for now.

Stupidism commented 6 years ago

For redux-form


  constructor(props) {
    super(props);

    // This binding is necessary to make `this` work in the callback
    this.refUsername = this.refUsername.bind(this);
    this.refPassword = this.refPassword.bind(this);
  }

  componentDidMount() {
    setTimeout(() => {
      if(this.usernameRef.getValue()) {
        this.passwordRef.setState({...this.passwordRef.state, hasValue: true});
      }
    }, 100)
  }

  refUsername(component) {
    this.usernameRef = component.getRenderedComponent().refs.component;
  }
  refPassword(component) {
    this.passwordRef = component.getRenderedComponent().refs.component;
  }

            <Field
              name="username"
              withRef
              ref={this.refUsername}
              component={TextField}
            />

            <Field
              name="password"
              type="password"
              withRef
              ref={this.refPassword}
              component={TextField}
            />

My app is a little bit slow, so I added an insurance

  componentDidMount() {
    let times = 0;
    const interval = setInterval(() => {
      times += 1;
      if(this.usernameRef.getValue()) {
        this.passwordRef.setState({...this.passwordRef.state, hasValue: true});
        clearInterval(interval);
      } else if (times >= 10) {
        clearInterval(interval);
      }
    }, 100)
  }
Stupidism commented 6 years ago

Can't get value from chrome autofilled password field https://stackoverflow.com/questions/35049555/chrome-autofill-autocomplete-no-value-for-password

oliviertassinari commented 6 years ago

As far as I have been playing with the v1-beta branch, the issue has been fixed along the way. It could be the rewrite or an upgrade of react. I'm closing until we hear more about it. Thanks for the discussion here!

artalar commented 6 years ago

image The error still exist... material-ui@0.18.7 react@15.6.1 Chrome 60.0.3112.90

Stupidism commented 6 years ago

@artalar Just try the componentDidMount solution O(∩_∩)O

Ivan-Parushev commented 6 years ago

@Stupidism Thank you for the solution! I have tried all of the above and none of them worked. Maybe because most of them are 1-2 years old... Btw, this bug happens only in Chrome, Firefox is perfectly fine :)

Stupidism commented 6 years ago

@Ivan-Parushev I guess it's because the usage of ref has been changed. So is your problem solved or not?

stiofand commented 6 years ago

Not solved here, Im filling the values in from localStorage if they exist on componentDidMount, and same error with all latest versions.

Still waiting for a fix...

oliviertassinari commented 6 years ago

I'm locking the thread. This issue is 2 years old. As we are now focusing on the v1-beta branch. If anyone has a reproduction example, please open a new issue for the v1-beta branch.

tsmirnov commented 5 years ago

It's been 3 years now. This issue still exists with the latest react and material ui versions.