I found a way that works with Chrome, Firefox and Edge:
- Set the name and ID of all of your inputs to random.
- Put some hidden rubbish in a span element in the field prompt.
Even when you rename / reID (??) each input, the browser uses the prompt to guess and still offers autocomplete. So, I did this in the prompt:
First/Given N<span style="display:none">fmkdgnkdfjgh</span>ame
The browser doesn't see this as a Name prompt. I did the same with Email, Mobile, Postcode and they all stopped offering autocomplete. Happy days!
I combined this into a small library:
var formFields = []; // Holds table of random element IDs vs original IDs/names
// Make sure our proposed new random field name is unique (it will be, but belt and braces)
var isUniqueFormElementID = iufeid = function (proposedID) {
for (var p = 0; p < formFields.length; p++) {
if (formFields[p].id == proposedID)
return false;
}
return true;
}
// Given an element and a prefix, generate a random field name, record it in formFields and change the element's ID and Name
var setFormElementID = sfeid = function (element, prefix) {
if (element.type.toLowerCase() == "text") {
do
newID = prefix + Math.floor(Math.random() * 1000000);
while (iufeid(newID) == false);
formFields.push({ id: newID, origID: element.id, origName: element.name });
element.id = newID;
element.name = newID;
}
}
// Return the index of an element's original ID in formFields
var findFormElement = ffe = function (origID) {
for (var p = 0; p < formFields.length; p++) {
if (formFields[p].origID == origID)
return p;
}
return -1;
}
// Return an element given its original ID
var getFormElement = gfe = function (origID) {
var idx = ffe(origID);
if (idx != -1)
return document.getElementById(formFields[idx].id);
else
return null;
}
// Remove an element from formFields and set its ID and Name back to the original
var resetFormElementID = removeFormElement = rfeid = rfe = function (origID) {
var idx = ffe(origID);
if (idx != -1) {
ele = document.getElementById(formFields[idx].origID);
ele.id = formFields[idx].origID;
ele.name = formFields[idx].origName;
formFields.splice(idx, 1);
return ele;
} else
return null;
}
// Remove all elements from formFields and set their ID and Name back to the original
var resetAllFormElementIDs = removeAllFormElements = rafeids = rafae = function () {
for (var p = 0; p < formFields.length; p++) {
ele = document.getElementById(formFields[p].id);
ele.id = formFields[p].origID;
ele.name = formFields[p].origName;
}
formFields = [];
}
// Return and obfuscate the prompt text of a field
var obfuscatePrompt = oP = function (promptText) {
var words = promptText.split(" ");
for (var p=0; p<words.length; p++)
words[p] = words[p][0] + "<span style='display:none'>fmkdgnkdfjgh</span>" + words[p].substring(1);
return words.join(" ");
}
// Main call
//
// form Form. The form object. If null, defaults to the first form found in document.forms.
// promptClassName String. The class name of the tags that contain the prompt text
// elementPrefix String. The prefix prepended to each element ID and name. If null, Defaults to "fld_".
var thwarteAutoFill = taf = function(form, promptClassName, elementPrefix) {
if (form == null) {
if (document.forms.length > 0) {
form = document.forms[0];
}
}
if (elementPrefix == null) {
elementPrefix = "fld_";
}
if (form != null && typeof promptClassName === "string") {
for (var p = 0; p < form.elements.length; p++)
sfeid(form.elements[p], elementPrefix);
prompts = document.getElementsByClassName(promptClassName);
for (p = 0; p < prompts.length; p++)
prompts[p].innerHTML = oP(prompts[p].innerText);
}
}
I call thwarteAutoFill(form, promptClassName, prefix) when the page has loaded, which randomises the text field IDs and names and looks for any element with the class name promptClassName and obfuscates the words inside those elements.
Then when I want to get a reference to a field I call gfe("origID") and it returns the correct element.
I also have a resetAllFormElementIDs function (untested as of writing this) that puts everything back as it was so I can call it before posting the form.
Convoluted, but seems to work ;-)