Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How fix issue with chrome auto complete overlap with labels in vuetify?

When trying to create a login form with outlined text fields in Vutify, the chrome autocomplete overlap with labels,

<v-text-field
  v-model="email"
  label="e-mail"
  name="email"
  outlined
  prepend-icon="mdi-account"
  type="text"
  required
>
</v-text-field>

enter image description here

you can regeneare here please fill and submit, then go back.

like image 519
PRAJIN PRAKASH Avatar asked Aug 05 '20 11:08

PRAJIN PRAKASH


2 Answers

This is how I have fixed this issue.

It seems our main problems are the following:

  • The autofill from Chrome, at loading page, not made interface react, letting the design like in your image.
  • So at the time of injection, we should do a fix ourself but no event, from Chrome, can inform us when login/password are auto-filled.

It's interesting to see any click from the browser window FROM USER automatically inform reactivity and all work fine again but it's not work FROM trigger/dispatch internal way.

So first, we need to find a way to react after login/password autofill. And second, we need to fix ourself the design because only a FROM USER action made the design work fine again.

1. React after autofilling at loading page

  • Like Harkness mention it, we can try to check :-webkit-autofill at regular interval while X second after code was mounted to see if an autofilling was injected (work fine for Chrome/Firefox/Edge from my test)
  • Another solution is to use the animationstart event (see here: https://github.com/material-components/material-components-web/issues/4447#issuecomment-580401216)

I use the first solution:

export default {
  //...
  data() {
    return {
      //...
      autofillFix: false,
    }
  },
  //...
  mounted() {
    this.autoLoginCheckingInterface()
  },
  //...
  autoLoginCheckingInterface() {
    // each 100ms we check if the issue was produced
    let intervalDetectAutofill = setInterval(() => {
      if (
        // we target at least one of the stuff that will be affected by autofill
        // to do our checking
        document.querySelectorAll('input[type="password"]:-webkit-autofill')
          .length > 0
      ) {
        // and we inform the system about the issue if it is produced
        this.autofillFix = true

        // we stop to check if issue was produced
        clearInterval(intervalDetectAutofill)
      }
    }, 100)

    // if after 3s nothing appear, means no autofill was made
    setTimeout(() => {
      if (intervalDetectAutofill) {
        clearInterval(intervalDetectAutofill)
        intervalDetectAutofill = null
      }
    }, 3000)
  },
  //...
}
<!--
we will inject `.autofill-fix` class to be able fix design ourself at time of this bug occur
--> 
<v-text-field
      ...
      :class="{ 'autofill-fix': autofillFix }"
      ...
      label="Email address or username"
      ...
      dense
      outlined
      @focus="autofillFix = false"
/>
<!--
we use @focus to let the normal behavior take again the lead
because we know this USER ACTION will made Chrome work well again
-->
<v-text-field
      ...
      :class="{ 'autofill-fix': autofillFix }"
      ...
      label="Password"
      type="password"
      ...
      dense
      outlined
      @focus="autofillFix = false"
/>

2. Fix ourself the design

We can see what are the change when v-text-field is filled. Without content, we can see this:

before

And after autofilling, we can see this:

after

So from the red part, we can see the following code need to be injected at time of .autofill-fix presence to fix the design in the proper way

.autofill-fix.v-text-field--outlined.v-input--dense .v-label {
  left: -28px!important;
  transform: translateY(-16px) scale(.75);
}

Note: You need change the CSS selector if you not use outlined or dense. Be careful about the specificity of selector https://specificity.keegan.st/. In fact, you need adapt the fixed change to your design

like image 50
Bruno J. S. Lesieur Avatar answered Sep 18 '22 12:09

Bruno J. S. Lesieur


Another way is to defined like @elazard suggest here an autofill variable like this

data () {
        return {
            login: null,
            password: null,
            autofill: false,
            intervalDetectAutofill: null
        }
    },
<v-text-field
    v-model="password"
    type="password"
    label="Password"
    :placeholder="autofill ? ` ` : null"
/>

With the solution given by @adam-reis, in the mounted() of the login page

mounted () {
        // search for autofill every 100ms
        this.intervalDetectAutofill = setInterval(() => {
            if (document.querySelectorAll("input[type=\"password\"]:-webkit-autofill").length > 0) {
                this.autofill = true
            }
        }, 100)

        // clean interval if needed after 3s
        setTimeout(() => {
            if (this.intervalDetectAutofill) {
                clearInterval(this.intervalDetectAutofill)
                this.intervalDetectAutofill = null
            }
        }, 3000)
    },

And of course setting autofill to false if user input

watch: {
        password () {
            this.autofill = false
        },
        autofill () {
            // clean interval if autofill detected or user input
            if (this.intervalDetectAutofill) {
                clearInterval(this.intervalDetectAutofill)
                this.intervalDetectAutofill = null
            }
        }
    },
like image 34
Harkness Avatar answered Sep 20 '22 12:09

Harkness