Disable Chrome Autofill
A client came to us with an annoyance they were experiencing with their React app UX. Their app was related to real estate and investors, so they are constantly entering multiple addresses, contact info, and numeric values as part of their data entry process. The annoyance they described was that every time they went to a field in their forms, Chrome would pop up the autofill with values from past entries. They were looking to disable chrome autofill functions that interrupted workflow.
The presence of the autofill dropdown was a visual annoyance, but also poses a risk for data accuracy, if a user accidentally selected one of those values, not only would it set the incorrect field value, but autofill’s behavior could also lead to it filling in MULTIPLE fields based on one autofill value being selected. This behavior is most prominent with addresses. For example, stored addresses. If you pick an autofill value for the street name in an address, Chrome will attempt to fill in as many address fields as it can like, city, state, zip, phone number, and email.
Finding the Chrome Autofill Solution at the Root
While autofill’s behavior is useful for personal computers, for a business application it is neither appropriate nor useful, and is even a risk.
Therefore, our goal was to find a way to disable autofill. The first and most obvious way to do it is to disable it in Chrome’s settings. This can be done, but the client has hopes of providing access to the application to outside clients, so it cannot be expected for all users to disable autofill as a prerequisite to using the application. The solution would have to come from elsewhere.
The next thought was to turn to disabling Chrome autofill programmatically. When we first started researching the problem we found this was common for many developers, but we found a number of conflicting/different recommendations and solutions. As well, for every solution posted, there were always comments underneath with people reporting it did not work. When we tried the various recommendations, we found they initially worked for a few page loads, but the autofill would always come back.
Correcting Autofill Through Trial and Error
The first solution we tried was using the input “autocomplete” attribute. People were saying to set this to a myriad of possibilities, such as “off”, “no”, “reset-password”, etc. We found that each time we set the field to use these values autofill would initially be disabled, but after a few page loads autofill would eventually return. Though the “autocomplete” attribute does seem related to autofill, it appears that as of now it is unreliable and only has a limited lasting effect on autofill.
The thing we did notice about the “autocomplete” attribute was that if you set it to a new value, Chrome would not immediately apply autofill to it. It would take a few page loads until it returned. Using this observation, we decided to dynamically set the “autocomplete” value to a UUID for each page load. This worked for some fields, but not others (most notably address fields). So we were met with partial success, but had to find a solution for the address fields.
Going back to our research and the recommended solutions, we found another. A solution we saw was to add a hidden field that’s a duplicate of the field you did not want to be autofilled. We found mixed success with this method, but again it seemed intermittent. We then thought about how the address autofill worked, it seemed Chrome would use related fields to determine if the set of fields represented an address. So our idea was to flood the pool of fields with dummy fields so Chrome would be confused and not be able to determine if the set were address fields. This actually worked!
Control Autofill in Chrome for React Based UX Application
So now we know that we have to populate the input “autocomplete” attribute with some value that will be unique. Also, we know that certain input names trigger the Chrome functionality. And in our testing, we found that it took a lot of dummy fields to throw Chrome off. Some sets of fields would be OK with three, but we ultimately found that for 100% effectiveness, 9 dummy fields were required.
With that in mind, we created a version of the code to work in a project which had jQuery available.
The jQuery version:
// ndrAutoFillOff.js
var ndrAutoFillOff = {
decoyFieldsWrapperClass: '__ndrAutoFillOff__',
decoyFieldInputName: 'state_city_address__afo__',
decoyFieldInputCount: 9,
init: function() {
$('body').on('focus', 'input', function() {
$('.' + ndrAutoFillOff.decoyFieldsWrapperClass).remove();
$(this).before(
'<div class="' + ndrAutoFillOff.decoyFieldsWrapperClass + '" style="display:none">' +
('<input name="' + ndrAutoFillOff.decoyFieldInputName + '" type="text" />').repeat(ndrAutoFillOff.decoyFieldInputCount) +
'</div>'
);
this.autocomplete = ndrAutoFillOff.getUUID();
});
},
getUUID: function() {
var dt = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}
}
$(function(){
ndrAutoFillOff.init();
});
In this code, whenever a user will draw focus on an input field, a specific number of decoy inputs will be created within a div element that hides them all. Each of these hidden inputs will have a name that Chrome will find interesting enough to apply its autofill functionality. In addition to this, the “autocomplete” attribute of the current focused input is populated with a randomly generated UUID value. And when a user inevitably shifts focus away to another input, any existing hidden div inputs will be removed and new ones will be generated.
Now, looking at this code, there isn’t a lot of jQuery involved. It would be better to remove the dependency on jQuery so that it is easier to include in more projects. So we developed the following plain Javascript version.
The Plain Javascript version:
// ndrAutoFillOff.js
var ndrAutoFillOff = {
decoyFieldsWrapperClass: '__ndrAutoFillOff__',
decoyFieldInputName: 'state_city_address__afo__',
decoyFieldInputCount: 9,
init: function(element) {
element.addEventListener('focus', ndrAutoFillOff.applyAutoFillOff, true);
},
applyAutoFillOff: function(event) {
var element = event.target;
if (!element.tagName || 'input' !== element.tagName.toLowerCase()) {
return;
}
var existing = document.querySelectorAll('.' + ndrAutoFillOff.decoyFieldsWrapperClass);
Array.prototype.forEach.call(existing, function(node) {
node.parentNode.removeChild(node);
});
element.insertAdjacentHTML(
'beforebegin',
'<div class="' + ndrAutoFillOff.decoyFieldsWrapperClass + '" style="display:none">' +
('<input name="' + ndrAutoFillOff.decoyFieldInputName + '" type="text" />').repeat(ndrAutoFillOff.decoyFieldInputCount) +
'</div>'
);
element.autocomplete = ndrAutoFillOff.getUUID();
},
getUUID: function() {
var dt = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (dt + Math.random() * 16) % 16 | 0; dt = Math.floor(dt / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}
}
ndrAutoFillOff.init(document.body);
This script does the exact same thing without having to include jQuery.
To include this plain Javascript file in your site, just add it before the closing body tag:
<html>
<head>
<title>Example</title>
</head>
<body>
<!-- content -->
<script src="/ndrAutoFillOff.js"></script>
</body>
</html>
With this code, the Chrome autofill functionality should be disabled. Hopefully this solution worked for you as well. Visit our blog for other handy solutions for everyday users and programmers.