DEV Community

loading...
Cover image for How to prevent Chrome form auto fill on Vue?

How to prevent Chrome form auto fill on Vue?

İbrahim Turan
・3 min read

When you logged in website, Chrome ask that do you want to save credentials for next visiting. If you accept that, Chrome saves your password then fill every password field(fields which types set as password) with your password on the web site.

This is expected behavior of this feature but sometimes comes annoying to users. For example in web site you have a field for API secret key and you decided to make that field type as password for security then Chrome thinks, this is login form and filling with your credential to form automatically. Today I will show how to prevent this behavior.

I made researches about how to prevent this behavior but answers or libraries I found for this behavior won't worked. So I decided to make my implementation and share with it.

Reason of That Behavior

As I mentioned before when form has password field and you saved your credentials to Chrome for that web site, Chrome things that, you are attempting to login this web site and fills every password field automatically.

Solution

Solution I found is very simple. I will implement with Vue on article but I think it could be easily implemented with React as well. My solution has 3 steps;

  • Settype='text' and add autocomplete="off" to all inputs in form for initial render.
  • When user focused password field, change field type as password
  • If user blur the input with empty value change input type as text.

Implementation in Vue

I will pass through application setup steps. I created to vue 2 app with default settings. Then added to simple login form on src/App.vue file shown below.

<template>
  <div id="app">
    <div v-if="isloggedin" class="welcome">
      Welcome {{username}}
    </div>
    <div v-else id="form-wrapper">
      <label for="username">Username: </label>
      <input
        v-model="username" 
        class="form-input" 
        type="text" 
        name="username" 
        value=""
      />
      <label for="password">Password: </label>
      <input 
        v-model="password"
        class="form-input"
        type="password"
        name="password"
        value=""
      />
      <button class="block" type="button" @click="saveCredentials">
        Submit Form
      </button>
    </div>
  </div>
</template>

<script>

export default {
  name: 'App',
  data() {
    return {
      username: '',
      password: '',
      isloggedin: false
    }
  },
  methods: {
    saveCredentials() {
      this.isloggedin = true;
    }
  }
}
</script>

<style>
#app {
  display: flex;
  flex: 1;
  height: 100vh;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

#form-wrapper {
  flex-shrink: 1;
  display:flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
}

.form-input {
  margin: 4px 0px;
}

.block {
  width: 100%;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Assume that we visited and login this web site before and saved credentials to Chrome. On next visit to site the login form will looks like shown below.

before-solution

To prevent this behavior, firstly we need to set input types as reactive and hold it in state. For initial render we need to set as text to input type.

<input 
  v-model="password"
  class="form-input"
  :type="fieldTypes.password" // change this as reactive
  name="password"
  value=""
/>
Enter fullscreen mode Exit fullscreen mode
data() {
  return {
    username: '',
    password: '',
    isloggedin: false,
    fieldTypes: { // add this for change input type
      password: 'text',
    }
  }
},
Enter fullscreen mode Exit fullscreen mode

Then need to add @focus and @blur events to password input and trigger callback function for that events.

<input 
  v-model="password"
  class="form-input"
  :type="fieldTypes.password"
  name="password"
  value=""
  @focus="handleType"
  @blur="handleType"
/>
Enter fullscreen mode Exit fullscreen mode
handleType(event) {
  const { srcElement, type } = event;
  const { name, value } = srcElement;

  if(type === 'blur' && !value) {
    this.fieldTypes[name] = 'text'
  } else {
    this.fieldTypes[name] = 'password'
  }
}
Enter fullscreen mode Exit fullscreen mode

Lastly to prevent chrome suggestions we need to add autocomplete="off" to all inputs. You could add autocomplete="new-password" to password field for strong password suggestions from browser. The final password field code looks like shown above.

<input 
  v-model="password"
  class="form-input"
  :type="fieldTypes.password"
  name="password"
  value=""
  @focus="handleType"
  @blur="handleType"
  autocomplete="off"
/>
Enter fullscreen mode Exit fullscreen mode

After all the final version of App.vue looks like this.

<template>
  <div id="app">
    <div v-if="isloggedin" class="welcome">
      Welcome {{username}}
    </div>
    <div v-else id="form-wrapper">
      <label for="username">Username: </label>
      <input
        v-model="username" 
        class="form-input" 
        type="text" 
        name="username" 
        value=""
        autocomplete="off"
      />
      <label for="password">Password: </label>
      <input 
        v-model="password"
        class="form-input"
        :type="fieldTypes.password"
        name="password"
        value=""
        @focus="handleType"
        @blur="handleType"
        autocomplete="off"
      />
      <button class="block" type="button" @click="saveCredentials">
        Submit Form
      </button>
    </div>
  </div>
</template>

<script>

export default {
  name: 'App',
  data() {
    return {
      username: '',
      password: '',
      isloggedin: false,
      fieldTypes: {
        password: 'text',
      }
    }
  },
  methods: {
    saveCredentials() {
      this.isloggedin = true;
    },
    handleType(event) {
      const { srcElement, type } = event;
      const { name, value } = srcElement;

      if(type === 'blur' && !value) {
        this.fieldTypes[name] = 'text'
      } else {
        this.fieldTypes[name] = 'password'
      }
    }
  }
}
</script>

<style>
#app {
  display: flex;
  flex: 1;
  height: 100vh;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

#form-wrapper {
  flex-shrink: 1;
  display:flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
}

.form-input {
  margin: 4px 0px;
}

.block {
  width: 100%;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Discussion (0)