Skip to content

Instantly share code, notes, and snippets.

@jonathantneal
Created September 11, 2018 14:56
Show Gist options
  • Star 44 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jonathantneal/d462fc2bf761a10c9fca60eb634f6977 to your computer and use it in GitHub Desktop.
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 {} }
@srgpsk
Copy link

srgpsk commented Mar 18, 2019

So helpful, thank you for sharing this!

@evild70
Copy link

evild70 commented Mar 22, 2019

👍

@n3ssi3
Copy link

n3ssi3 commented Apr 30, 2019

@XmlmXmlmX
Copy link

Edge seems not working

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