JavaScript and Google Chrome autofill

JavaScript and Google Chrome autofill

ยท

4 min read

Hi there ๐Ÿ‘‹

Autofill is a common feature in all modern browsers where browsers normally ask our permission to preserve the data entered in form fields and auto populate it next time when we visit the same page. Isn't that nice ? :)

But there are few things we need to be aware of as a web dev about browser autofill, especially when we have to deal with floating label input fields, like this one.

floating-label.gif

  • Every browser implements autofill capability differently

  • Chrome browser doesn't dispatch a change or any event when autofills an input field

  • As no event is dispatched, it is not possible to detect autofill event using JavaScript

  • Autofill is handled by browser automatically without user interaction hence it is not a trusted action

  • Because autofill is not a trusted action, we will not be able to read the value of autofilled input field in JavaScript until an user action is performed

With that being said, a floating label of an input field in chrome browser generally overlaps with autofilled value as there is no event being dispatched.

autofill-issue.PNG

So how can we overcome this issue? CSS to the rescue! We can detect an autofilled input field via CSS using -webkit-autofill pseudo class and make the label float without overlapping with value.

/* select an input element autofilled by browser */
const autofilledInput = document.querySelector('input:-webkit-autofill');

/* check if the input field is autofilled - not null if autofilled */
if(autofilledInput) {
   /* code to float label */
}

or

input:-webkit-autofill {
   /*styles to remediate float label issue*/
}

In Angular, with Angular-Material components, I would do like this,

login.component.html

/*floatLabel attribute can be set to make the label float always 
or auto. Default style is auto. Listen to focus event of 
input field and reset the label float style to auto*/
<form class="login-form">
  <mat-form-field [floatLabel]="floatStyle" appearance="outline"> 
    <mat-label>Username</mat-label>
    <input matInput placeholder="Username" (focus)="resetFloatStyle()">
  </mat-form-field>

  <mat-form-field [floatLabel]="floatStyle" appearance="outline">
    <mat-label>Password</mat-label>
    <input type="password" matInput placeholder="Password" (focus)="resetFloatStyle()">
  </mat-form-field>
</form>

login.component.ts

import {Component, OnInit} from '@angular/core';

@Component({
  selector: 'login-component',
  styleUrls: ['login.component.css'],
  templateUrl: 'login.component.html',
})
export class LoginComponent implements OnInit {

floatStyle='auto';

ngOnInit() {
   /* wait for browser autofills the input field and set the label
   float style to always if autofilled */
   setTimeout(()=>{
    const autofilledInput = document.querySelector('input:-webkit-autofill');

    if(autofilledInput) {
       this.floatStyle='always';
    }
  }, 500);
}

/* change float style back to auto after user interaction */
resetFloatStyle() {
  if(this.floatStyle !== 'auto') {
     this.floatStyle='auto';
  }
 }
}

Thanks for reading! Stay tuned ๐Ÿ™‚