Better Password Fields with jQuery

February 8, 2010

The ‘whether or not to show plain text in password fields for usability’ situation has never really been resolved to my satisfaction; plain-text fields are clearly much more usable and less confusing than obscured passwords, but what if the person using the plain-text field is sat in a public place? Showing their password for just anyone to see would be ludicrous.

The iPhone style of obscuring everything except the last letter is a good compromise that offers a combination of security and usability, and there are plenty of great guides out there on how to implement this in your web pages.

But it’s still based on the flawed assumption that the user is always going to be somewhere public. And it’s not 100% secure anyway because if someone watches each letter as it’s typed over your shoulder, depending on what the password is, it could be very easy to remember. The point is that we don’t have to rely on a compromise when a solution is easy to implement.

The solution is to hand the initiative over to the visitor and let them decide for themselves whether to show the password in plain text or not. Then we don’t have to either use a semi-hidden, semi-secure way of presenting the field, and we don’t have to make the choice of whether to show plain or obscured text. All we need to do is add a simple link after the password field which will convert the obscured password field to a standard text field, thus revealing the password.

The code

Start off with the standard HTML that you would normally use when requiring a visitor to enter their password, probably something like the following:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Better Password Fields</title>
  </head>
  <body>
    <form action="#" method="post">
      <label for="pass">Password:</label><input id="pass" name="pass" type="password">
    </form>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript">

    </script>
  </body>
</html>

The password field is specified as a password field so that if the visitor has JavaScript disabled the field will be obscured by default – better to err on the side of caution right?

We haven’t hardcoded a link to the page that will convert the password field into a plain text field; if JS is disabled the link will be completely useless. The best way to have an element on the page that requires JavaScript be enabled for it to work is to add the element with JavaScript in the first place – that way if JavaScript is disabled, the useless link won’t be added.

That’s all of the underlying HTML that we need – nothing more and nothing less, the very definition of semantic. Everything else we need we can add using the script, which we’ll look at next.

Preparing the form for revealed password fields

Let’s setup the initial part of the script which would run on page load; we left an empty script element at the bottom of the HTML, add the following code to it:

(function($) {
  $("form").find("input[type='password']").each(function(val) {
    var input = $(this);

    //insert link to show plain-text
    $("<a>").text("Show password").addClass("show-plain").attr({
      title: "Show the password in plain text",
      href: "#"
    }).insertAfter(input);
  });
})(jQuery);

All of our code will reside within a self-executing anonymous function which we pass the jQuery object into. Our function accepts the jQuery object using the $ parameter so it is safely aliased within the local scope of our function, which should offer protection from any other libraries that may be in use on whatever pages the code ends up on.

All we need to do at this stage is prep our password fields by adding the ’show plain text’ links after each password field. We first select all of the input fields that have a type of password (that’s just one in this example, but there could be more on pages out in the wild), then for each of the selected elements we create a new anchor and insert it directly after the current input field.

The new anchor has its title and href attributes set (some browsers won’t treat it as a link if it doesn’t have a href), and we give it a class name of show-plain (mostly so that we can select it in just a moment but potentially also for styling purposes).

Our page should now look like this, with the new link directly after the password field:

Better Password Fields 1

A simple, unassuming link. Next we need to make our new link(s) work; directly before the last line of code (})(jQuery);) add the following:

//add click handler for show-plain link(s)
$(".show-plain").live("click", function() {

  //cache selector
  var input = $(this).prev();

  //create new text input
  $("<input>").attr({
    id: input.attr("id"),
    type: "text",
    name: input.attr("name")
  }).val(input.val()).addClass(input.attr("class")).insertAfter(input.prev());
  input.remove();

  //change link text and attributes
  $(this).text("Hide password").removeClass("show-plain").addClass("show-hidden").attr({
    title: "Obscure the text"
  });

  //stop link being followed
  return false;
});

We use the live() method to add a click handler for the ’show plain text’ link because, as you can probably tell from the code above, the class name of the link changes. Using live() means that we don’t have to re-bind the click event every time we create a new link; the live() method uses event delegation which attaches a listener for this event to the specified element’s parent instead of binding directly to the element itself.

Within the anonymous function added as a parameter to the live() method we first cache a reference to the input element directly before the link that was clicked, so the variable will always refer to the correct input element regardless of which link is clicked. We cache it because we’ll be referring to it several times and we don’t want to have to select it from the document each time we want to do something with it.

Next we create our replacement text input, which we set to a standard text type so that its contents will be clearly visible. We copy any text that has already been entered into the password field, and any class names that may have been given to it. We then insert the new text field and remove the password field. It’s the old switcheroo, plain and simple, but it will look as if any text already entered into the password field is magically revealed. The following image shows the two states:

Better Password Fields 2

Reapplying the obscured text

Now we just need to add the code that will turn the revealed text back into obscured text, just in case the visitor needs to hide the password again. We’ve given the choice back to the visitor of whether the password should be visible or not, but we’d better give them the choice to hide it again too. After the click handler for the show-plain link add the following code:

//add click handler for show-plain link(s)
$(".show-hidden").live("click", function() {

  //cache selector
  var input = $(this).prev();

  //create new password input
  $("<input>").attr({
    id: input.attr("id"),
    type: "password",
    name: input.attr("name")
  }).val(input.val()).addClass(input.attr("class")).insertAfter(input.prev());
  input.remove();

  //change link text and attributes
  $(this).text("Show password").removeClass("show-hidden").addClass("show-plain").attr({
    title: "Show the password in plain text"
  });

  //stop link being followed
  return false;
});

This is pretty much the reverse of what we did in order to show the text; we just remove the plain text field, copying its value, id and any class names, and then replace it with a new input of type password. We also adjust the link again to reflect the new state. We should find that when we load the page we can enter text into the field and switch between plain and obscured text as in the previous screenshot in any common mainstream browser.

Summary

In terms of usability nothing can be better than giving your visitors a clear and simple choice; in this case whether or not to show a password in plain text or obscured text. We saw how easy it was to add this simple solution to a page – just a couple of lines of code. So instead of offering a compromise we can offer a solution, and improve the usability and effectiveness of password fields on our sites at the same time.

30 Responses to “Better Password Fields with jQuery”

  1. Samir Talwar says:

    Awesome idea—I’ll have to try this when I get home. One question though: is there a reason why we can’t just alter the type attribute of the tag? Does this not work in some browsers?

  2. [...] This post was mentioned on Twitter by Dan Wellman, Creed Huckaby. Creed Huckaby said: Very nice… RT @danwellman: Better password fields with jQuery: http://bit.ly/cko0rn [...]

  3. Dan Wellman says:

    @Samir Thanks :D Yeah, switching the type attribute didn’t seem to work too well (don’t think I could get it working in any browser) so this really seemed the easiest method.

  4. Social comments and analytics for this post…

    This post was mentioned on Twitter by danwellman: Better password fields with jQuery: http://www.danwellman.co.uk/better-password-fields-with-jquery/ RT and enjoy :D…

  5. Ozh says:

    I’ve used a similar trick in the UI of all my recent projects (screenshot here for example). I find a checkbox more suitable than a link, btw

    I also added a function to revert all password fields to their hidden default state, but I can’t remember why now :)

  6. Benjam says:

    Great post, good info.

    I notice that you left off the “name” attribute when transferring the attributes from the old input element to the new input element. Is this by design? I would imagine that the name attribute would be rather important otherwise the password field won’t be submitted when the form is submitted.

    Also… you have a missing > character in your HTML on the closing password label tag.

  7. Avinash says:

    nice work Dan,
    But I still don’t understand how the password filed value in plain text is visible…
    Any way Congrates & Best Regards

    ~Avinash

  8. Dan Wellman says:

    @Benjam,

    Thanks for pointing that out, I completely forgot the name attribute. The code is now updated to include it :)

  9. Dan Wellman says:

    @Ozh, a checkbox sounds great instead of the link :)

  10. I wrote a jQuery password mask plugin a little while ago which uses a checkbox to unmask. It can be found on github:

    http://github.com/damian/jQuery-passwordMask

    I’ve set a couple of options to allow whoever uses it to show cleartext passwords by default if needs be and also to customise the checkbox text.

    It’s a little outdated now though as it doesn’t harness jQuery 1.4’s construction of dom elements like your great example here.

  11. [...] Dan Wellman » Better Password Fields with jQuery This is a jQuery powered solution that allows users to see passwords that they are typing in password fields. By default, the value is hidden, but a quick click can allow them to see it. (tags: jquery javascript design user-experience forms) [...]

  12. Ben says:

    This is really a cool idea. I could use that in a customer project right now where its possible to show the password to the user again if he wants that.

  13. ESN says:

    That’s pretty cool! It’ll be handy for pages like Edit Profile or Registration.

  14. [...] Better Password Fields with jQuery Via / DZone [...]

  15. SM says:

    Nice solution. Thanks

  16. [...] Better Password Fields with jQuery [...]

  17. [...] avoir fouillé le web, je suis tombé sur une première solution de Dan Wellman. Et la deuxième vient de Stefan [...]

  18. merih akca says:

    2 very important questions to make this GREAT script more useful

    1) How can we position the “Show Password” text link to wherever we want in the page ? it is very annoying to get restricted to put the link right after the password input box. Can you please give a simple script modification ?

    For example, put the text link after a image file in page.

    2) How can you include checkbox right beside the text link (ckeckbox + text link to do the same function)

    THANKS !!

  19. Dan Wellman says:

    @merih from a usability perspective it makes sense for the link (or checkbox) to be close to the field it’s attached to. In my example there is just the one text field, but in a form with many input fields it would need to be close. That said, you could easily adjust the position using CSS, and if you needed to you could change the element that the link is inserted after.

    There are some comments above that link to variations of scripts that use checkbox. This script could be modified by inserting a checkbox instead of the link. You’d just need to check for the checked attribute before deciding whether to show or hide the password

  20. merih akca says:

    Thanks for the comments, Dan

    After I tried soo many things and countless modifications based on your explanation,I got no result. I do not know where I do the mistake.

    All I want is to see a simple chekbox and Show password positioned with CSS.

    I am really hoping you could give more hint, or better a script sniplet to see a light on the way. Would you ?

    There are many other Show/Hide password scripts but somehow I see that your solution is more suitable to use really. I believe many people would agree on that as well.

    thanks again

  21. [...] Better Password Fields with jQuery [...]

  22. Leland Beres says:

    THANKS FOR GUIDE!

  23. oy764df says:

    very good!
    Thank you very much!
    From Japan

  24. Ahmet says:

    Great post thanks. I’m using your technique on checkboxes and working well. The questions is, how can I make possible it one-and-one for all checkboxes iteratively?

  25. Dan Wellman says:

    not sure what you mean, please clarify?

  26. Ahmet says:

    Sorry for my english! I need control all checkboxes. Actually I solved my problem almost. But I need little help.

    var inx = $(“form input:checkbox”).toArray();

    inx is a object not a clear array. I can change values and attributes by the getAttribute() but input.remove(); doesn’t work. I didn’t find any function to remove the input variable. And I didn’t find any function to make a clear array variable inx. jQuery documentation says use: alert($(‘li’).toArray()); and result is: [, ] but I’m getting an object array when trying $(“form input:checkbox”).toArray();

  27. Eve Niland says:

    My developer is trying to persuade me to move to .net from PHP. I have always disliked the idea because of the costs. But he’s tryiong none the less. I’ve been using WordPress on a number of websites for about a year and am concerned about switching to another platform. I have heard excellent things about blogengine.net. Is there a way I can import all my wordpress content into it? Any help would be really appreciated!Richmond Roofing Service, 6731 Pickett Dr., Richmond, TX 77469 – (281) 973-7855

  28. Dan Wellman says:

    Yes. I think there is a blog import for Wordpress in BlogEngine.net. Although it’s been a long time since I used it so I can’t remember the details :)

    I would probably use Umbraco these days instead of BlogEngine.net

  29. Nick Tredwell says:

    A very good solution to the problem.

    However live() is now removed from jQuery 1.9, so the lines containing them need changing. e.g.
    $(“.show-plain”).live(“click”, function() {
    becomes
    $(document).on(“click”, “.show-plain”, function() {

Leave a Reply

My Books