Detecting autofilled fields in Javascript

One of my colleagues is transitioning to the front-end team that I used to be a part of. To prepare him mentally for his journey into front-end development, I’ve been sending him a newsletter I call Front-End Hack of the Day. I’m posting them to Medium now for the world to enjoy.

When the browser autofills a form field, it adds some styling to highlight which fields it has edited. In Chrome, as you can see above, it adds a lovely yellow background color.

In principle, I think this is a good idea, as it shows the user which fields they should pay attention to in order to see if everything was correctly filled out. However, it will most likely clash with the rest of your sites’ styling, so it would be nice if we could have some more control over it.

input:-webkit-autofill {
// Much nicer
background-color: bisque;
}

You can add styles by using the vendor prefixed pseudo-class -webkit-autofill, but if you need to run some Javascript when a field gets autofilled, it gets a lot trickier.

In @klarna/ui, Klarna’s open-source UI component toolkit, we use the floating label pattern. The label is initially displayed like a placeholder, and when you start typing it transitions to a small label at the top of the field.

This is done by listening for a change event and adding the class is-filled to the field, which then applies the appropriate zooming and positioning.

However, no event whatsoever is fired when a field is autofilled, so there’s no way to know when to add the class.

And this is where the hack comes in…

Change event through animation

We can’t know when the field value changes through autofill, but that’s not the only thing that happens when it gets autofilled — some styles are also applied!

Unfortunately, we can’t really listen for a style change, but we can listen for the start of an animation, and we can start an animation in response to autofilling using the previously mentioned -webkit-autofill pseudo-class.

@keyframes onAutoFillStart {  from {/**/}  to {/**/}}
@keyframes onAutoFillCancel { from {/**/} to {/**/}}
input:-webkit-autofill {
// Expose a hook for JavaScript when autofill is shown
// JavaScript can capture 'animationstart' events
animation-name: onAutoFillStart;

// Make the background color become yellow really slowly
transition: background-color 50000s ease-in-out 0s;
}
input:not(:-webkit-autofill) {
// Expose a hook for JS onAutoFillCancel
// JavaScript can capture 'animationstart' events
animation-name: onAutoFillCancel;
}

To clarify what’s going on here, we are running the onAutoFillStart animation when the psuedo class -webkit-autofill is active, which it will be when Chrome autofills the input and changes the background color.

Now we can listen for the start of that animation from within our Javascript.

const AUTOFILLED = 'is-autofilled'
const onAutoFillStart = (el) => el.classList.add(AUTOFILLED)
const onAutoFillCancel = (el) => el.classList.remove(AUTOFILLED)
const onAnimationStart = ({ target, animationName }) => {
switch (animationName) {
case 'onAutoFillStart':
return onAutoFillStart(target)
case 'onAutoFillCancel':
return onAutoFillCancel(target)
}
}
document.querySelector('input').addEventListener('animationstart', onAnimationStart, false)

Now whenever either the onAutoFillStart or onAutoFillCancel animations start playing, our corresponding functions will run, where we will add or remove the is-autofilled class, or do whatever else we want to do.

Perfectly aligned labels with orange color to show that the field has been autofilled

I hope this hack will be useful to you. If you want to take a peek at how this is used within @klarna/ui, you can find the implementation of the Field on Github.