Material-ui: [TextField] Form autofill doesn't update floating label text on textfield

Created on 29 May 2015  ·  75Comments  ·  Source: mui-org/material-ui

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

bug 🐛 TextField external dependency v0.x

Most helpful comment

If anyone is still here, I just set this prop InputLabelProps={{ shrink: true }} on the TextField that this effected. Was the best solution for our team.

All 75 comments

This is probably a good place to start...

@illogikal could you post of gif that?

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.

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

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.

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.

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?

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

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

That looks like a different issue.

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

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.

Exact same problem:

s

Any idea, guys?

Experiencing the same issue.

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

@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

any solution to fire onChange event ?

@antoinerousseau Is this going to be merged in master?

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

This will be fixed soon ;)

image

nice @nathanmarks, thanks!!

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

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.

@adamtal3 it's autoComplete="off"

@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.

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. :)

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.

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" />

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

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

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} />
    }
}

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.].

@mbrookes Not fixed as I tested.

@Stupidism Details?

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

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

  "name": "material-ui",
  "version": "0.18.3",
  "name": "react",
  "version": "15.6.0",



md5-f7a2844706b5476282e07a6c64e29edb



Google Chrome   59.0.3071.86 (Official Build) (64-bit)
OS  Linux
JavaScript  V8 5.9.211.31

image

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

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)
  }

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!

image
The error still exist...
[email protected]
[email protected]
Chrome 60.0.3112.90

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

@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 :)

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

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...

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.

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

@tschaub Haha, like the ios position-fixed input gets focused problem.

@tsmirnov Time for you to get stuck in and fix it then. 😜

There is a css solution to this bug

// Selects label that comes right after the autofilled input
input:-webkit-autofill + label {
    // Insert your active label styles
}

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.

I am facing the same issue.

There is a css solution to this bug

// Selects label that comes right after the autofilled input
input:-webkit-autofill + label {
    // Insert your active label styles
}

Can you please explain what this means ?

There is a css solution to this bug

// Selects label that comes right after the autofilled input
input:-webkit-autofill + label {
    // Insert your active label styles
}

Can you please explain what this means ?

:-webkit-autofill selects autofilled fields by browser. Place your label right next to input and select it with :-webkit-autofill selector. If you need more help please share your current html structure.

There is a css solution to this bug

// Selects label that comes right after the autofilled input
input:-webkit-autofill + label {
    // Insert your active label styles
}

Can you please explain what this means ?

:-webkit-autofill selects autofilled fields by browser. Place your label right next to input and select it with :-webkit-autofill selector. If you need more help please share your current html structure.

Sure! Here is my HTML Please help. Thanks
https://pastebin.com/yjJCip3r

There is a css solution to this bug

// Selects label that comes right after the autofilled input
input:-webkit-autofill + label {
    // Insert your active label styles
}

Can you please explain what this means ?

:-webkit-autofill selects autofilled fields by browser. Place your label right next to input and select it with :-webkit-autofill selector. If you need more help please share your current html structure.

Sure! Here is my HTML Please help. Thanks
https://pastebin.com/yjJCip3r

Your labels come right after the inputs, so you dont have to do anything with html.
Just select your labels right next to autofilled inputs and set them your active label styles as shown below.

.mdl-textfield__input:-webkit-autofill + .mdl-textfield__label {
    // Active label styles here
    top: -20px; // Just an example
    transform: scale(0.75); // Just an example
}

Uh, @kishan3 I think you're lost. MDL is this way --> https://github.com/google/material-design-lite/issues/4827 😆

(Although given that MDL is dead Jim, perhaps you've come to the right place after all!)

Ah damn! Its confusing with names. :laughing: @mbrookes One question though: can we use material UI directly into HTMLs with CDN links? I never realised MDL is dead :cry:

@kishan3 You can, although as it says in the docs, this means the client has to download the entire library, at least the first time until it's cached, whereas building it locally means you can optimize which components are included.

What's the solution?

This issue concerns v0.x.

@oliviertassinari this stil exists in v3.4.0.

In my case, i'm using a dropdown, when the user selects something in the dropdown then it sets the value to the state, the TextField associated to the value does not floats the label.

Edit: As it seems, if i init the TextField values with null then the float won't move when new value is passed. Fixed by initialising the values in state with empty string instead of null

If anyone is still here, I just set this prop InputLabelProps={{ shrink: true }} on the TextField that this effected. Was the best solution for our team.

@tom-con thanks man, it worked for me perfectly

screen shot 2019-01-24 at 10 47 44 pm
this problem still exists in 2019...

If anyone is still here, I just set this prop InputLabelProps={{ shrink: true }} on the TextField that this effected. Was the best solution for our team.
I was really confused and you solved the problem! Best recommended solution!

This is a v0.x issue (2015), please refer to #14427.

There is a css solution to this bug

// Selects label that comes right after the autofilled input
input:-webkit-autofill + label {
    // Insert your active label styles
}

@ozturkcangokkaya Hi this css solution works fine in Chrome. But when i check my form in firefox, floating label is not working. Do you have any idea why webkit-autofill affects firefox?

Please see #14427 for v4.

The best solution is to stop using Materialize and use Bootstrap or another library, seeing that you have to come up with a workaround and Google seems to have no interest in fixing the issue.

If anyone is still here, I just set this prop InputLabelProps={{ shrink: true }} on the TextField that this effected. Was the best solution for our team.

Thank you, I am using this: InputLabelProps={{ shrink: form.password }} , and it works perfectly.

<TextField
                id="loginPassword"
                label="Login Password"
                type="text"
                fullWidth
                value={form.password}
                onChange={(e) => setAttribute('form.password', e.target.value)}
                InputLabelProps={{ shrink: form.password }}
              />

I solved my problem installing lodash.merge on my project then I realised I was filling the text field component incorrectly it was because I thought the redux behaves should be the same when I use nested objects.

As you can see, I am not filling correctly when I mixing two nested objects.

image

I solved this using the library and so it was.
image

Note that the latest version of Material-UI (v4.9.0) supports it by default.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

activatedgeek picture activatedgeek  ·  3Comments

ghost picture ghost  ·  3Comments

TimoRuetten picture TimoRuetten  ·  3Comments

FranBran picture FranBran  ·  3Comments

ryanflorence picture ryanflorence  ·  3Comments