Autofill does not trigger onChange

11,323

Solution 1

I stumbled across this issue because I had the same problem. Not in React, but the problem is universal. Maybe this will help anyone else who stumbles upon this.

None of the other answers actually answer the problem. The problem as described by the OP is that Chrome doesn't set the value of the inputs until there has been user interaction with the page. This can be clicking on the page, or even typing random things into the console.

After user interaction has occurred the value of the inputs are set and the change event is fired.

You can even visually see this, as the styling of the autofilled text is different when first presented and changes to the styling of the inputs once interaction has taken place.

Also: triggering a click or setting focus or whatever from code doesn't help, only real human interaction.

So polling for the value is not a solution, because the value will stay empty if the page is not clicked. Also stating that you can't rely on the change event is not really relevant, since the event is properly fired, upon the delayed setting of the value. It's the indefinite delay that's the problem.

You can however poll for the existence of Chrome's pseudo CSS classes. In Chrome 83 (june 2020) these are :-internal-autofill-selected and :-internal-autofill-previewed. These do change regularly however. Also, they are not directly present after rendering. So you should set a sufficient timeout, or poll for it.

Sloppy example in vanilla JavaScript:

var input = document.getElementById('#someinput');

setTimeout(() => {
   if (input.matches(':-internal-autofill-selected')) {
      /* do something */
   }
}, 500);

You still can't get the value at this point, so in that regard it still doesn't solve the problem, but at least you can enable the submit button based on the existence of autofilled data (as the OP wanted to do). Or do some other visual stuff.

Solution 2

Using oninput instead of onchange would do the trick

Solution 3

The answer would be to either disable autocomplete for a form using autocomplete="off" in your form or poll at regular interval to see if its filled.

The problem is autofill is handled differently by different browsers. Some dispatch the change event, some don't. So it is almost impossible to hook onto an event which is triggered when browser autocompletes an input field.

  • Change event trigger for different browsers:

    • For username/password fields:

      1. Firefox 4, IE 7, and IE 8 don't dispatch the change event.
      2. Safari 5 and Chrome 9 do dispatch the change event.
    • For other form fields:

      1. IE 7 and IE 8 don't dispatch the change event.
      2. Firefox 4 does dispatch the change change event when users select a value from a list of suggestions and tab out of the field.
      3. Chrome 9 does not dispatch the change event.
      4. Safari 5 does dispatch the change event.

You best options are to either disable autocomplete for a form using autocomplete="off" in your form or poll at regular interval to see if its filled.

For your question on whether it is filled on or before document.ready again it varies from browser to browser and even version to version. For username/password fields only when you select a username password field is filled. So altogether you would have a very messy code if you try to attach to any event.

You can have a good read on this HERE

Have a look at this thread: Detecting Browser Autofill

Solution 4

No need to trigger a click event, I think it could be better if you set the email state in componentDidMount like this

this.setState({ email: document.getElementById('email').value })

so once componentDidMount() is invoked you will get the email filled by Chrome and update the state then render the submit button and make it enabled.

You can read more about React life cycle on this link

Solution 5

event.target.click() will "simulate" a click and fire onClick() events, but doesn't act like a physical click in the browser window.

Have you already tried using focus() instead of (or in addition to) click()? You could try putting the focus on your input element and then check to see if the value is then set. If that works, you could add this.setState({ email: event.target.value }) on focus as well as on click.

Share:
11,323
naezith
Author by

naezith

Updated on June 14, 2022

Comments

  • naezith
    naezith almost 2 years

    I have a login form, when the page is opened, Chrome automatically fills the credentials. However, onChange event of input elements are not being triggered.

    Clicking anywhere on the page makes them registered in value attribute of the input, which is what we need. I tried doing event.target.click(), that did not help.

    In the onChange I set the values into state like:

    this.setState({ email: event.target.value })
    

    And the submit button is disabled if email.length === 0.

    So even if page shows that credentials are filled, submit button still looks disabled.

    Since clicking anywhere registers the values, clicking the submit button also registers them before submitting. So it works perfectly.

    It is not about timing though, field is never being filled. When I open the Developer Console and check, the value field is empty, until I click somewhere.

    Only issue here is that the button looks disabled because email input value is empty until something is clicked. Is there a hacky solution for this?