Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Created September 11, 2018 14:56
Show Gist options
  • Select an option

  • Save jonathantneal/d462fc2bf761a10c9fca60eb634f6977 to your computer and use it in GitHub Desktop.

Select an option

Save jonathantneal/d462fc2bf761a10c9fca60eb634f6977 to your computer and use it in GitHub Desktop.
Detect autofill in Chrome, Edge, Firefox, and Safari
export default scope => {
// match the filter on autofilled elements in Firefox
const mozFilterMatch = /^grayscale\(.+\) brightness\((1)?.*\) contrast\(.+\) invert\(.+\) sepia\(.+\) saturate\(.+\)$/
scope.addEventListener('animationstart', onAnimationStart)
scope.addEventListener('input', onInput)
scope.addEventListener('transitionstart', onTransitionStart)
function onAnimationStart(event) {
// detect autofills in Chrome and Safari by:
// - assigning animations to :-webkit-autofill, only available in Chrome and Safari
// - listening to animationstart for those specific animations
if (event.animationName === 'onautofillstart') {
// during autofill, the animation name is onautofillstart
autofill(event.target)
} else if (event.animationName === 'onautofillcancel') {
// during autofill cancel, the animation name is onautofillcancel
cancelAutofill(event.target)
}
}
function onInput(event) {
if ('data' in event) {
// input events with data may cancel autofills
cancelAutofill(event.target)
} else {
// input events without data are autofills
autofill(event.target)
}
}
function onTransitionStart(event) {
// detect autofills in Firefox by:
// - listening to transitionstart, only available in Edge, Firefox, and Internet Explorer
// - checking filter style, which is only changed in Firefox
const mozFilterTransition =
event.propertyName === 'filter' &&
getComputedStyle(event.target).filter.match(mozFilterMatch)
if (mozFilterTransition) {
if (mozFilterTransition[1]) {
// during autofill, brightness is 1
autofill(event.target)
} else {
// during autofill cancel, brightness is not 1
cancelAutofill(event.target)
}
}
}
function autofill(target) {
if (!target.isAutofilled) {
target.isAutofilled = true
target.setAttribute('autofilled', '')
target.dispatchEvent(new CustomEvent('autofill', { bubbles: true }))
}
}
function cancelAutofill(target) {
if (target.isAutofilled) {
target.isAutofilled = false
target.removeAttribute('autofilled')
target.dispatchEvent(new CustomEvent('autofillcancel', { bubbles: true }))
}
}
return () => {
scope.removeEventListener('animationstart', onAnimationStart)
scope.removeEventListener('input', onInput)
scope.removeEventListener('transitionstart', onTransitionStart)
}
}
input,
select,
textarea {
transition: background-color 50000s, color 50000s, filter 50000s;
&:-webkit-autofill {
animation-duration: 50000s;
animation-name: onautofillstart;
}
&:not(:-webkit-autofill) {
animation-duration: 50000s;
animation-name: onautofillcancel;
}
}
@keyframes onautofillstart { from {} }
@keyframes onautofillcancel { from {} }
@n3ssi3
Copy link

n3ssi3 commented Apr 30, 2019

@XmlmXmlmX
Copy link

Edge seems not working

@vitoraugustto
Copy link

vitoraugustto commented Jan 12, 2026

Thank you! It worked really well on Safari!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment