Brett Veenstra
Brett Veenstra

Reputation: 48524

How do you disable browser autocomplete on web form field / input tags?

How do you disable autocomplete in the major browsers for a specific input (or form field)?

Upvotes: 3260

Views: 1468667

Answers (30)

Alessandro Marchisio
Alessandro Marchisio

Reputation: 545

I created a function that receives as input the reference to the password field and the character you want to display This function:

  • adds a text field that will be displayed as a normal text field
  • hides the password field
  • handles keyboard events on the new text field: each time a key is pressed, the password field is written; an x ​​character (to be chosen) is added to the text field, it also handles or inhibits any cursor movement or copy/paste

Browser does not detect password field focus and does not whisper anything

here is an implementation https://codepen.io/alemarch/pen/ByazxZd

function noWhisperPassword(originalField, passChar = "*") {
  var newElm = $("<input type=text>")
    .attr("draggable", "false")
    .css("user-select", "none");

  $(originalField).after(newElm);

  $(originalField).hide();

  $(newElm).on(
    "keypress",
    (_insKey = function (e, _originalField, _selStart, _selEnd) {
      var selStart = $(this).get(0).selectionStart;
      var selEnd = $(this).get(0).selectionEnd;
      var lungh = $(this).get(0).value.length;

      if (_selStart != undefined) {
        selStart = _selStart;
      }
      if (_selEnd != undefined) {
        selEnd = _selEnd;
      }

      console.log("_insKey", this, e, _originalField, selStart, selEnd, lungh);

      if (typeof originalField == "undefined") {
        originalField = _originalField;
      }

      var oldValue = $(originalField).val();

      $(this).val($(this).val() + passChar);

      var newValue =
        oldValue.substring(0, selStart) +
        String.fromCharCode(e.which) +
        oldValue.substring(selEnd, lungh);

      $(originalField).val(newValue);

      //$(originalField).val($(originalField).val() + String.fromCharCode(e.which));

      console.log("Password: " + $(originalField).val());
      return false;
    })
  );

  $(newElm).on("beforecopy copy", function () {
    console.log(e.type, e);
  });

  $(newElm).on("keydown", async function (e) {
    var selStart = $(this).get(0).selectionStart;
    var selEnd = $(this).get(0).selectionEnd;
    var lungh = $(this).val().length;
    console.log(selStart, selEnd);
    switch (e.which) {
      case 86: //V
        if (e.ctrlKey) {
          console.log("Detect ctrl+v");
          e.preventDefault();

          try {
            var fraseDaCopiare = await navigator.clipboard.readText();

            for (var k = 0; k < fraseDaCopiare.length; k++) {
              console.log(
                "copy: ",
                fraseDaCopiare,
                k,
                fraseDaCopiare[k],
                selStart,
                selEnd
              );

              _insKey.call(
                $(newElm),
                { which: fraseDaCopiare[k].charCodeAt(0) },
                $(originalField),
                selStart + k,
                k == 0 ? selEnd : selStart + k
              );
            }
          } catch (err) {
            console.error("clipboadData error", err);
          } finally {
            return false;
          }

          navigator.clipboard
            .readText()
            .then((text) => {
              console.log("Pasted content: ", text);
            })
            .catch((err) => {
              console.error("Failed to read clipboard contents: ", err);
            });

          return false;
        }
        break;
      case 45: //ins
        if (e.shiftKey) {
          return false;
        }
        break;
      case 36: //inizio
      case 37: //
      case 38:
      case 39:
        return false;
      case 46: //canc
      case 8: //backspace
        var oldValue = $(originalField).val();
        var newValue =
          oldValue.substring(0, selStart) + oldValue.substring(selEnd, lungh);

        console.log(
          "newValue",
          "0" + "-" + selStart,
          oldValue.substring(0, selStart),
          selEnd + "-" + lungh,
          oldValue.substring(selEnd, lungh),
          "{" + lungh + "}"
        );

        if (newValue.length >= lungh) {
          newValue = newValue.substring(0, lungh - 1);
        }

        if (lungh == 0) {
          newValue = "";
        }

        $(originalField).val(newValue);
        break;
    }
  });

  $(newElm).on("drop dragstart", function (e) {
    console.log("Detect drop/drag");
    return false;
  });

  $(newElm).on("mousemove", function (e) {
    var selStart = $(this).get(0).selectionStart;
    var selEnd = $(this).get(0).selectionEnd;
    console.log("Detect move", selStart, selEnd, e.button, e.which, e.buttons);
    e.preventDefault();
    return false;
  });
}

noWhisperPassword(".noWhisper", "-");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<label for="myPassword">Enter password</label>
<input type="" id="myPassword" name="myPassword" class="noWhisper">

Upvotes: 0

Amir Forsati
Amir Forsati

Reputation: 5970

Let me do it for you:

let lastValue = '';
let passwordInput = document.querySelector('#password');
passwordInput.addEventListener('input', (event) => {
    if (event.inputType !== "insertFromPaste" && Math.abs(passwordInput.value.length - lastValue.length) > 1) {
        passwordInput.value = '';
    }
    lastValue = passwordInput.value;
});

If you want to allow pasting just remove event.inputType !== "insertFromPaste" from if condition.

Upvotes: 0

franmcod
franmcod

Reputation: 497

The only one that worked for me was aria-autocomplete="none"

Upvotes: 2

Jon Adams
Jon Adams

Reputation: 25147

We actually used the randomly-named input fields idea for one site:

It was a medical software web app to run a doctor's office. However, many of our clients were surgeons who used lots of different workstations, including semi-public terminals. So, they wanted to make sure that a doctor who doesn't understand the implication of auto-saved passwords or isn't paying attention can't accidentally leave their login information easily accessible.

Of course, this was before the idea of private browsing that is starting to be featured in Internet Explorer 8, Firefox 3.1, etc. Even so, many physicians are forced to use old school browsers in hospitals with IT that won't change.

So, we had the login page generate random field names that would only work for that post. Yes, it's less convenient, but it's just hitting the user over the head about not storing login information on public terminals.

Upvotes: 24

Alex from Jitbit
Alex from Jitbit

Reputation: 60832

NB: I can swear that browser devs are coming back to this page learning new ways to fight our efforts

March 2024

Looks like latest Chromium browsers (v.122) do not autosuggest for inputs liek this:

autocomplete="otp"

Which apparently makes them think, this is a 2FA-password.

I went a little further and discovered that

autocomplete="RaNd0m$tring"

also works. By randomString I mean a new value, every time.

Upvotes: 0

dsuess
dsuess

Reputation: 5347

Sometimes even autocomplete=off would not prevent to fill in credentials into the wrong fields, but not a user or nickname field.

This workaround is in addition to apinstein's post about browser behavior.

Fix browser autofill in read-only and set writable on focus (click and tab)

 <input type="password" readonly
     onfocus="this.removeAttribute('readonly');"
     onblur="this.setAttribute('readonly', true);"/>

Update:

Mobile Safari sets cursor in the field, but it does not show the virtual keyboard. The new fix works like before, but it handles the virtual keyboard:

<input id="email" readonly type="email" onfocus="if (this.hasAttribute('readonly')) {
    this.removeAttribute('readonly');
    // fix for mobile safari to show virtual keyboard
    this.blur();    this.focus();  }" />

Live Demo https://jsfiddle.net/danielsuess/n0scguv6/

// UpdateEnd

Because the browser auto fills credentials to wrong text field!?

I notice this strange behavior on Chrome and Safari, when there are password fields in the same form. I guess the browser looks for a password field to insert your saved credentials. Then it auto fills (just guessing due to observation) the nearest textlike-input field, that appears prior the password field in the DOM. As the browser is the last instance and you can not control it.

This readonly-fix above worked for me.

Upvotes: 202

Sergio
Sergio

Reputation: 36

A combo that worked for me in 2023 (checked in Chrome browser):

<input
   name='nm-0.239458' // generated with `nm-${ Math.random() }`
   placeholder='Nаme' // where 'а' is cyrilic, it looks exactly like latin 'a'
/>

Upvotes: -1

SomeOne
SomeOne

Reputation: 111

This worked for me:

1- Add autocomplete="off" onto <form> element.

2- Add hidden <input> with autocomplete="false" as a first children element of the form with display: none.

<form autocomplete="off" method="post" action="">
    <input autocomplete="false" name="hidden" type="text" style="display:none;">
    ...

Upvotes: 4

Cesc
Cesc

Reputation: 27

Unfortunately the problem goes on... and it seems no action done by main browsers, or even worst, some actions are done just against any solution. The option:

autocomplete="new-password"

is not working on some browsers now, as the autocomplete is done with the password generator (that confuses the user as the value is hidden).

For some empty input fields, explicitly the case

type="url"

it is really complicated to avoid incorrect autocompletion, but an unbreakable space instead of an empty value do the trick (spaces don't do)...at the cost of some garbagge included in the form (and one of this days the browsers will also autocomplete that)

Very sad.

Upvotes: 1

Murat Yıldız
Murat Yıldız

Reputation: 12050

In addition to

autocomplete="off"

Use

readonly onfocus="this.removeAttribute('readonly');"

for the inputs that you do not want them to remember form data (username, password, etc.) as shown below:

<input type="text" name="UserName" autocomplete="off" readonly 
    onfocus="this.removeAttribute('readonly');" >

<input type="password" name="Password" autocomplete="off" readonly 
    onfocus="this.removeAttribute('readonly');" >

Upvotes: 35

Stokely
Stokely

Reputation: 15897

DO NOT USE JAVASCRIPT to fix this!!

Use HTML to address this problem first, in case browsers are not using scripts, fail to use your version of the script, or have scripts turned off. Always layer scripting LAST on top of HTML.

  1. For regular input form fields with "text" type attributes, add the autocomplete="off" on the element. This may not work in modern HTML5 browsers due to user browser override settings but it takes care of many older browsers and stops the autocomplete drop-down choices in most. Notice, I also include all the other autocomplete options that might be irritating to users, like autocapitalize="off", autocorrect="off", and spellcheck="false". Many browsers do not support these but they add extra "offs" of features that annoy data entry people. Note that Chrome for example ignores "off" if a user's browsers are set with autofill enabled. So, realize browser settings can override this attribute.

EXAMPLE:

<input type="text" id="myfield" name="myfield" size="20" value="" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" placeholder="Enter something here..." title="Enter Something" aria-label="Something" required="required" aria-required="true" />
  1. For username and password input type fields, there is some limited browser support for more specific attributes for autocomplete that trigger the "off" feature". autocomplete="username" on text inputs used for logins will force some browsers to reset and remove the autocomplete feature. autocomplete="new-password" will try and do the same for passwords using the "password" type input field. (see below). However, these are propriety to specific browsers and will fail in most. Browsers that do not support these features include Internet Explorer 1-11, many Safari and Opera desktop browsers, and some versions of iPhone and Android default browsers. But they provide additional power to try and force the removal of autocomplete.

EXAMPLE:

<input type="text" id="username" name="username" size="20" value="" autocomplete="username" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" placeholder="Enter username here..." title="Enter Username" aria-label="Username" required="required" aria-required="true" />
<input type="password" id="password" name="password" size="20" minlength="8" maxlength="12" pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,12}" value="" autocomplete="new-password" autocapitalize="off" autocorrect="off" spellcheck="false" tabindex="0" placeholder="Enter password here..." title="Enter Password: (8-12) characters, must contain one number, one uppercase and lowercase letter" aria-label="Password" required="required" aria-required="true" />

NOW FOR A BETTER SOLUTION!

Because of the splintered support for HTML5 by standards bodies and browsers, many of these modern HTML5 attributes fail in many browsers. So, some kids turn to script to fill in the holes. But that's lazy programming. Hiding or rewriting HTML using JavaScript makes things worse, as you now have layers upon layers of script dependencies PLUS the HTML patches. Avoid this!

The best way to permanently disable this feature in forms and fields is to simply create a custom "id"/"name" value each time on your 'input' elements using a unique value like a date or time concatenated to the field id and name attribute and make sure they match (e.g. "name=password_{date}").

<input type="text" id="password_20211013" name="password_20211013" />

This destroys the silly browser autocomplete choice algorithms sniffing for matched names that trigger past values for these fields. By doing so, the browsers cannot match caches of previous form data with yours. It will force "autocomplete" to be off, or show a blank list, and will not show any previous passwords ever again! On the server side, you can create these custom input "named" fields and still identify and extract the correct field from the response from the user's browser by simply parsing the first part of the id/name. For example "password_" or "username_", etc. When the field's "name" value comes in you simply parse for the first part ("password_{date}") and ignore the rest, then extract your value on the server.

Easy!

Upvotes: 1

zinczinc
zinczinc

Reputation: 554

None of the provided answers worked on all the browsers I tested. Building on already provided answers, this is what I ended up with, (tested) on Chrome 61, Microsoft Edge 40 (EdgeHTML 15), IE 11, Firefox 57, Opera 49, and Safari 5.1. It is wacky due to many trials; however, it does work for me.

<form autocomplete="off">
    ...
    <input type="password" readonly autocomplete="off" id="Password" name="Password" onblur="this.setAttribute('readonly');" onfocus="this.removeAttribute('readonly');" onfocusin="this.removeAttribute('readonly');" onfocusout="this.setAttribute('readonly');" />
    ...
</form> 

<script type="text/javascript">
    $(function () {           
        $('input#Password').val('');
        $('input#Password').on('focus', function () {
        if (!$(this).val() || $(this).val().length < 2) {
            $(this).attr('type', 'text');
        }
        else {
            $(this).attr('type', 'password');
        }
    });
    $('input#Password').on('keyup', function () {
        if (!$(this).val() || $(this).val().length < 2) {
            $(this).attr('type', 'text');
        }
        else {
            $(this).attr('type', 'password');
        }
    });
    $('input#Password').on('keydown', function () {
        if (!$(this).val() || $(this).val().length < 2) {
            $(this).attr('type', 'text');
        }
        else {
            $(this).attr('type', 'password');
        }
    });
</script>

Upvotes: 1

HackerMF
HackerMF

Reputation: 595

For React you can try to put this code either now under a form or above password input or between email and password inputs

export const HackRemoveBrowsersAutofill = () => (
  <>
    <input type="email" autoComplete="new-password" style={ { display: 'none' } } />
    <input type="password" autoComplete="new-password" style={ { display: 'none' } } />
  </>
)

One of the examples:

<input type="email"/>
<HackRemoveBrowsersAutofill/>
<input type="password"/>

Upvotes: 1

MAKSTYLE119
MAKSTYLE119

Reputation: 48

you only need autocomplete attribute for this problem you can visit this page for more information

<input type="text" name="foo" autocomplete="off" />

Upvotes: 2

2022 September

Some browsers such as Google Chrome does not even care the value of autocomplete attribute. The best way to stop getting suggestions is changing the name attribute of the input to something that changes time to time

As of September 2022, browsers will not provide autocomplete for one time passwords

So we can use otp as the field name.

<input name="otp">

Upvotes: 1

softcod.com
softcod.com

Reputation: 580

This will fix this problem

autocomplete="new-password"

Upvotes: 1

tripleJ
tripleJ

Reputation: 21

Since the behavior of autocomplete is pretty much unpredictable over different browsers and versions, my approach is a different one. Give all input elements for which you want to disable autofill the readonly attribute and only disable it on focus.

  document.addEventListener('click', (e) => {
    readOnlys.forEach(readOnly => {
      if (e.target == readOnly) {
        readOnly.removeAttribute('readonly', '');
        readOnly.style.setProperty('pointer-events', 'none');
      } else {
        readOnly.setAttribute('readonly', '');
        readOnly.style.setProperty('pointer-events', 'auto');
      }
    });
  });
  document.addEventListener('keyup', (e) => {
    if (e.key == 'Tab') {
      readOnlys.forEach(readOnly => {
        if (e.target == readOnly) {
          readOnly.removeAttribute('readonly', '');
          readOnly.style.setProperty('pointer-events', 'none');
        } else {
          readOnly.setAttribute('readonly', '');
          readOnly.style.setProperty('pointer-events', 'auto');
        }
      });
    }
  });

If you want to make sure that users can still access the fields if they have disabled JS, you can set all readonlys initially via JS on page load. You can still use the autocomplete attribute as a fallback.

Upvotes: 1

DLK
DLK

Reputation: 311

I was looking arround to find a solution to this but none of them worked proberly on all browsers.

I tried autocomplete off, none, nope, new_input_64, (even some funny texts) because the autoComplete attribute expects a string to be passed, no matter what.

After many searches and attempts I found this solution.

I changed all input types to text and added a bit of simple CSS code.

Here is the form:

<form class="row gy-3">
  <div class="col-md-12">
    <label for="fullname" class="form-label">Full Name</label>
    <input type="text" class="form-control" id="fullname" name="fullname" value="">
  </div>
  <div class="col-md-6">
    <label for="username" class="form-label">User Name</label>
    <input type="text" class="form-control" id="username" name="username" value="">
  </div>
  <div class="col-md-6">
    <label for="email" class="form-label">Email</label>
    <input type="text" class="form-control" id="email" name="email" value="">
  </div>
  <div class="col-md-6">
    <label for="password" class="form-label">Password</label>
    <input type="text" class="form-control pswd" id="password" name="password" value="">
  </div>
  <div class="col-md-6">
    <label for="password" class="form-label">Confirm Password</label>
    <input type="text" class="form-control pswd" id="password" name="password" value="">
  </div>
  <div class="col-md-12">
    <label for="recaptcha" class="form-label">ReCaptcha</label>
    <input type="text" class="form-control" id="recaptcha" name="recaptcha" value="">
  </div>
</form>

The CSS code to hide password:

.pswd {
    -webkit-text-security: disc;
}

Tested on Chrome, Opera, Edge.

Upvotes: 0

step
step

Reputation: 2410

Always working solution

I've solved the endless fight with Google Chrome with the use of random characters. When you always render autocomplete with random string, it will never remember anything.

<input name="name" type="text" autocomplete="rutjfkde">

Hope that it will help to other people.

Update 2022:

Chrome made this improvement: autocomplete="new-password" which will solve it but I am not sure, if Chrome change it again to different functionality after some time.

Upvotes: 69

Dieter Bender
Dieter Bender

Reputation: 37

Browser ignores autocomlete on readonly fields. This code makes all writable filds readonly till it's focused.

$(_=>{$('form[autocomplete=off] [name]:not([readonly])').map((i,t)=>$(t).prop('autocomplete',t.type=='password'?'new-password':'nope').prop('readonly',!0).one('focus',e=>$(t).prop('readonly',!1)));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="post" autocomplete="off">
<input name="user" id="user" required class="form-control" />
<label class="form-label" for="user">New User</label>
<hr>
<input type="password" name="pass" id="pass" minlength="8" maxlength="20" />
<label class="form-label" for="pass">New Passwort</label>
</form>

Upvotes: 1

frank edekobi
frank edekobi

Reputation: 113

<input autocomplete="off" aria-invalid="false" aria-haspopup="false" spellcheck="false" />

i find it works for me on all browsers. When I make use of only the autocomplete it doesn't work except i combine all the attributes that you see. Also i got the solution from google form input field

Upvotes: 6

abernee
abernee

Reputation: 477

I was having trouble on a form which included input fields for username and email with email being right after username. Chrome would autofill my current username for the site into the email field and put focus on that field. This wasn't ideal as it was a form for adding new users to the web application.

It seems that if you have two inputs one after the other where the first one has the term 'user name' or username in it's label or ID and the next one has the word email in it's label or ID chrome will autofill the email field.

What solved the issue for me was to change the ID's of the inputs to not include those words. I also had to set the text of the labels to an empty string and use a javascript settimeout function to change the label back to what it should be after 0.01s.

setTimeout(function () { document.getElementById('id_of_email_input_label').innerHTML = 'Email:'; }, 10);

If you are having this problem with any other input field being wrongly autofilled I'd try this method.

Upvotes: -2

Abdul Wadud Somrat
Abdul Wadud Somrat

Reputation: 174

To disable the autocomplete of text in forms, use the autocomplete attribute of and elements. You'll need the "off" value of this attribute.

This can be done in a for a complete form or for specific elements:

  1. Add autocomplete="off" onto the element to disable autocomplete for the entire form.
  2. Add autocomplete="off" for a specific element of the form.

form

<form action="#" method="GET" autocomplete="off">
</form>

input

<input type="text" name="Name" placeholder="First Name" autocomplete="off">

Upvotes: 4

user1779049
user1779049

Reputation: 29

Define input's attribute type="text" along with autocomplete="off" works enough to turn off autocomplete for me.

EXCEPT for type="password", I try switching the readonly attribute using JavaScript hooking on onfocus/onfocusout event from others' suggestions works fine BUT while the password field editing begin empty, autocomplete password comes again.

I would suggest switching the type attribute regarding length of password using JavaScript hooking on oninput event in addition to above workaround which worked well..

<input id="pwd1" type="text" autocomplete="off" oninput="sw(this)" readonly onfocus="a(this)" onfocusout="b(this)" />
<input id="pwd2" type="text" autocomplete="off" oninput="sw(this)" readonly onfocus="a(this)" onfocusout="b(this)" />

and JavaScript..

function sw(e) {
    e.setAttribute('type', (e.value.length > 0) ? 'password' : 'text');
}
function a(e) {
    e.removeAttribute('readonly');
}
function b(e) {
    e.setAttribute('readonly', 'readonly');
}

Upvotes: 0

Alex from Jitbit
Alex from Jitbit

Reputation: 60832

I've been fighting this never-ending battle for ages now... And all tricks and hacks eventually stop working, almost as if browser devs are reading this question.

I didn't want to randomize field names, touch the server-side code, use JS-heavy tricks and wanted to keep "hacks" to a minimum. So here's what I came up with:

TL;DR use an input without a name or id at all! And track changes in a hidden field

<!-- input without the "name" or "id" -->
<input type="text" oninput="this.nextElementSibling.value=this.value">
<input type="hidden" name="email" id="email">

Works in all major browsers, obviously.

P.S. Known minor issues:

  1. you can't reference this field by id or name anymore. But you can use CSS classes. Or use $(#email').prev(); in jQuery. Or come up with another solution (there's many).
  2. oninput and onchange events do not fire when the textbox value is changed programmatically. So modify your code accordingly to mirror changes in the hidden field too.

Upvotes: 1

Shahid Malik
Shahid Malik

Reputation: 171

Very simple solution Just change the label name and fields name other than the more generic name e.g: Name, Contact, Email. Use "Mail To" instead of "Email". Browsers ignore autocomplete off for these fields.

Upvotes: 0

German
German

Reputation: 1166

Things had changed now as I tried it myself old answers no longer work.

Implementation that I'm sure it will work. I test this in Chrome, Edge and Firefox and it does do the trick. You may also try this and tell us your experience.

set the autocomplete attribute of the password input element to "new-password"

<form autocomplete="off">
....other element
<input type="password" autocomplete="new-password"/>
</form>

This is according to MDN

If you are defining a user management page where a user can specify a new password for another person, and therefore you want to prevent autofilling of password fields, you can use autocomplete="new-password"

This is a hint, which browsers are not required to comply with. However modern browsers have stopped autofilling <input> elements with autocomplete="new-password" for this very reason.

Upvotes: 10

thisisashwani
thisisashwani

Reputation: 1844

(It works in 2021 for Chrome (v88, 89, 90), Firefox, Brave, and Safari.)

The old answers already written here will work with trial and error, but most of them don't link to any official documentation or what Chrome has to say on this matter.

The issue mentioned in the question is because of Chrome's autofill feature, and here is Chrome's stance on it in this bug link - Issue 468153: autocomplete=off is ignored on non-login INPUT elements, Comment 160

To put it simply, there are two cases -

  • [CASE 1]: Your input type is something other than password. In this case, the solution is simple, and has three steps.

  • Add the name attribute to input

  • name should not start with a value like email or username. Otherwise Chrome still ends up showing the dropdown. For example, name="emailToDelete" shows the dropdown, but name="to-delete-email" doesn't. The same applies for the autocomplete attribute.

  • Add the autocomplete attribute, and add a value which is meaningful for you, like new-field-name

It will look like this, and you won't see the autofill for this input again for the rest of your life -

  <input type="text/number/something-other-than-password" name="x-field-1" autocomplete="new-field-1" />
  • [CASE 2]: input type is password
  • Well, in this case, irrespective of your trials, Chrome will show you the dropdown to manage passwords / use an already existing password. Firefox will also do something similar, and same will be the case with all other major browsers. 2
  • In this case, if you really want to stop the user from seeing the dropdown to manage passwords / see a securely generated password, you will have to play around with JS to switch input type, as mentioned in the other answers of this question.

2 Detailed MDN documentation on turning off autocompletion - How to turn off form autocompletion

Upvotes: 2

Rocket Fuel
Rocket Fuel

Reputation: 508

Here's the perfect solution that will work in all browsers as of May 2021!

TL;DR

Rename your input field names and field ids to something non-related like 'data_input_field_1'. Then add the &#8204; character into the middle of your labels. This is a non-printing character, so you won't see it, but it tricks the browser into not recognizing the field as one needing auto-completing, thus no built-in auto-complete widget is shown!

The Details

Almost all browsers use a combination of the field's name, id, placeholder, and label to determine if the field belongs to a group of address fields that could benefit from auto-completion. So if you have a field like <input type="text" id="address" name="street_address"> pretty much all browsers will interpret the field as being an address field. As such the browser will display its built-in auto-completion widget. The dream would be that using the attribute autocomplete="off" would work, unfortunately, most browsers nowadays don't obey the request.

So we need to use some trickery to get the browsers to not display the built-in autocomplete widget. The way we will do that is by fooling the browser into believing that the field is not an address field at all.

Start by renaming the id and the name attributes to something that won't give away that you're dealing with address-related data. So rather than using <input type="text" id="city-input" name="city">, use something like this instead <input type="text" id="input-field-3" name="data_input_field_3">. The browser doesn't know what data_input_field_3 represents. But you do.

If possible, don't use placeholder text as most browsers will also take that into account. If you have to use placeholder text, then you'll have to get creative and make sure you're not using any words relating to the address parameter itself (like City). Using something like Enter location can do the trick.

The final parameter is the label attached to the field. However, if you're like me, you probably want to keep the label intact and display recognizable fields to your users like "Address", "City", "State", "Country". Well, great news: you can! The best way to achieve that is to insert a Zero-Width Non-Joiner Character, &#8204;, as the second character in the label. So replacing <label>City</label> with <label>C&#8204;ity</label>. This is a non-printing character, so your users will see City, but the browser will be tricked into seeing C ity and not recognize the field!

Mission accomplished! If all went well, the browser should not display the built-in address auto-completion widget on those fields anymore!

Upvotes: 8

Alan M.
Alan M.

Reputation: 1369

I wanted something that took the field management completely out of the browser's hands, so to speak. In this example, there's a single standard text input field to capture a password — no email, user name, etc...

<input id='input_password' type='text' autocomplete='off' autofocus>

There's a variable named "input", set to be an empty string...

var input = "";

The field events are monitored by jQuery...

  1. On focus, the field content and the associated "input" variable are always cleared.
  2. On keypress, any alphanumeric character, as well as some defined symbols, are appended to the "input" variable, and the field input is replaced with a bullet character. Additionally, when the Enter key is pressed, and the typed characters (stored in the "input" variable) are sent to the server via Ajax. (See "Server Details" below.)
  3. On keyup, the Home, End, and Arrow keys cause the "input" variable and field values to be flushed. (I could have gotten fancy with arrow navigation and the focus event, and used .selectionStart to figure out where the user had clicked or was navigating, but it's not worth the effort for a password field.) Additionally, pressing the Backspace key truncates both the variable and field content accordingly.

$("#input_password").off().on("focus", function(event) {
    $(this).val("");
    input = "";

}).on("keypress", function(event) {
    event.preventDefault();

    if (event.key !== "Enter" && event.key.match(/^[0-9a-z!@#\$%&*-_]/)) {
        $(this).val( $(this).val() + "•" );
        input += event.key;
    }
    else if (event.key == "Enter") {
        var params = {};
        params.password = input;

        $.post(SERVER_URL, params, function(data, status, ajax) {
            location.reload();
        });
    }

}).on("keyup", function(event) {
    var navigationKeys = ["Home", "End", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"];
    if ($.inArray(event.key, navigationKeys) > -1) {
        event.preventDefault();
        $(this).val("");
        input = "";
    }
    else if (event.key == "Backspace") {
        var length = $(this).val().length - 1 > 0 ? $(this).val().length : 0;
        input = input.substring(0, length);
    }
});

Front-End Summary

In essence, this gives the browser nothing useful to capture. Even if it overrides the autocomplete setting, and/or presents a dropdown with previously entered values, all it has is bullets stored for the field value.


Server Details (optional reading)

As shown above, JavaScript executes location.reload() as soon as the server returns a JSON response. (This logon technique is for access to a restricted administration tool. Some of the overkill, related to the cookie content, could be skipped for a more generalized implementation.) Here are the details:

  • When a user navigates to the site, the server looks for a legitimate cookie.
  • If there isn't any cookie, the logon page is presented. When the user enters a password and it is sent via Ajax, the server confirms the password and also checks to see if the user's IP address is in an Authorized IP address list.
  • If either the password or IP address are not recognized, the server doesn't generate a cookie, so when the page reloads, the user sees the same logon page.
  • If both the password and IP address are recognized, the server generates a cookie that has a ten-minute life span, and it also stores two scrambled values that correspond with the time-frame and IP address.
  • When the page reloads, the server finds the cookie and verifies that the scrambled values are correct (i.e., that the time-frame corresponds with the cookie's date and that the IP address is the same).
  • The process of authenticating and updating the cookie is repeated every time the user interacts with the server, whether they are logging in, displaying data, or updating a record.
  • If at all times the cookie's values are correct, the server presents the full website (if the user is logging in) or fulfills whatever display or update request was submitted.
  • If at any time the cookie's values are not correct, the server removes the current cookie which then, upon reload, causes the logon page to be redisplayed.

Upvotes: 2

Related Questions