Better Passwords #2: “Show Password”

Tweet

For the previous post in this short series we looked at a script for creating masked password fields, and I’ve been very much moved by the strength of responses to that post. Boy, did you guys hate it! At the time I published it, I had reservations about certain aspects, but overall I thought it was a good idea.

Well now I’ve changed my mind! Having read through the comments and concerns that were posted, I don’t think it’s a good idea anymore. And it wasn’t so much the individual details — like the lack of autocomplete support, or the need to restrict the caret position — it was more the fact that it creates these restrictions without necessarily adding much benefit. That these password fields are not really safe from shoulder snooping, and not necessarily any easier to use than ordinary starred-out fields.

But still, we’re faced with the original problem — ordinary starred-out "password" fields do have poor usability, and it would be nice to find a better solution.

So in this post we’ll be looking at an alternative idea, something which a couple of you have already mentioned, and which the title of this post kinda gives away…

The “Show Password” Checkbox

At it’s heart, a far simpler and more straightforward approach than the masking-symbol solution, we simply add a checkbox beneath or next to the password field which, when checked, converts the field to plain-text so you can see it without any obfuscation:


A login form with a “show password” checkbox.

Now personally, I would never advocate a purely-plain password field, whatever the situation, but the point with this solution is that we give users control. We do, after all, invariably know when we’re safe from casual observers — I have my back to a wall right now, and anyway I’m alone in this room!

So we give users the option of seeing their password plain, and then leave it to them to think about when that’s safe. (Though having said that, a warning of some kind can’t hurt — the demo I’ve put together for this post has a note in the checkbox label saying that it’s not advisable in a public place.)

So here’s a script that adds this functionality to "password" fields, in a progressive and cross-browser way. Have a look at the demo, and grab a copy of the code:

Markup first

We start this example with exactly the same markup as last time:

<label for="pword">Password:</label>
<input type="password" id="pword" name="pword" />

But this time there’s no need to modify the existing markup at all, we’re just going to add to it with some new stuff. Firstly the checkbox and label which are the visible toggle, and then a secondary "text" field, which is what you see when you check the box.

Ideally, we would just flip the field type between "password" and "text" to achieve this, but naturally that won’t work in IE. So what we do instead is create a second, plain-text field, in the same context as the original, and then switch between them by toggling their display.

So what we end up with is markup like this:

<label for="pword">Password:</label>
<span>
    <input type="password" id="pword" name="pword" />
    <input type="text" id="pword" autocomplete="off" style="display:none;" />
    <label class="show-password" for="showpasscheckbox-1" title="Show the password as plain text">
        <input type="checkbox" id="showpasscheckbox-1" title="Show the password as plain text" />
        <span>Show Password</span>
    </label>
</span>

Now eagle-eyed observers will notice that both the original password field, and the new text field, have the same ID, thereby invalidating the DOM. I’ll be the first to admit that this is wrong, but it’s pragmatic — it’s not just the ID in fact, the script copies every attribute from the password field (except its name and type), so that it inherits the same appearance and behavior, and ultimately, comes out the same as its progenitor. You could remove that behavior from the script, but if so you’d need to replace it with known styling-hook semantics, such as a fixed class name (something that a third-party script like this could never assume to do).

You might also have spotted a sneaky autocomplete="off" in there, but relax! That’s just on the plain field to prevent duplication — autocomplete on the password field works just the same as normal.

Scripting last

The events we need to make this work are actually pretty simple. First of all, we have a change handler on both the password and text field, so that input into either one of them updates the value in the other. There’s no need to use a more immediate event than onchange, because by definition, you can’t view one field without removing focus from the other.

Then there’s a click handler on the checkbox itself, which toggles the display of the two fields — so that one of them is visible and one is hidden (with the text field being hidden by default). But there is also a small gotcha at this point, which means that whenever we toggle the fields, we should also update their values, ie. re-copy the value from the currently displayed field to the one about to be shown…

When navigating in the browser’s history from a submitted page back to the form, what you will find in some browsers is that one of the values is still there while the other has been deleted (In IE the password will still be there but the plain value deleted; in Opera it will be the other way round; in Firefox they’ll both be empty). These discrepancies (which arise from differences in browser security and event models) can cause the two values to become out of sync, so to keep them in sync, we just make sure that whenever we toggle the fields’ display, we also sync their values.

We also have to do something similar pre-submission. It’s possible that a user will come back in the history, to a snapshot state in the browser where the plain field was visible, then re-enter or edit that value and immediately re-submit, without ever toggling back to the password field. This presents a problem because the password field is the one with the submittable value in it; the plain field is just a readout, as it were. So to fix this we add a routine immediately prior to form submission (ie. a submit listener which doesn’t affect the native behavior), which copies the value from the plain field to the password field, if the plain field is the one that’s visible.

Intermezzo!

However one lingering security issue does remain in Opera, which I haven’t been able to prevent. One of Opera’s greatest strengths is also one of its greatest annoyances, viewed from a certain angle, which is that when you step back in Opera’s history, it doesn’t reload the page — not even from cache — it literally re-creates the previous processor snapshot of that page. So if, for example, you come to a page from a link in a dropdown menu, when you go back to the previous page, the menu will still be open, exactly as you left it — the load event won’t fire, and there’s no other cue to the developer that a page load has happened at all … because it hasn’t!

The same situation is true, to a lesser extent, for all cached page views in Opera, and what it means for users is that all cached page views are faster. But what it means for our script is that if you submit the form with the plain-password visible, then come back in the history, the plain password will still be visible — right there, potentially exposing your password to observers, if you weren’t expecting it.

I don’t think there’s any way we can catch that situation, because as far as script events are concerned, nothing has happened — no events fire, because no events have occurred. Weird huh? And yet totally sensible!

I think we take can some comfort in the fact that Opera users — who tend as a general demographic to be more tech-literate, not to mention very familiar with how their browser works — probably won’t be too surprised by this. I mean, I live in Opera most of the time, and one of the things I love most about it is the way you can step-back through form submissions without triggering script events!!

Too easy!

So that’s pretty much all there is to it — no nasty surprises here!

I suppose if we take simplicity to heart, it should be evident just from an overview that this is a better solution than the masked password field. It’s cleaner, simpler, and doesn’t require the forced-removal of native behaviors to make the damn thing work! But it isn’t perfect, and if this solution is really a good one, perhaps it would still be better if it were implemented by the browser itself.

Join me soon for the third and last post in this series, where I’ll be looking at something small and cute that you can throw-in almost anywhere!

Thumbnail credit: Clearly Ambiguous

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.deathshadow.com deathshadow60

    This feels a little saggy around the midsection for what it does — I’ve got the feeling that you’ve got 10k doing 2-3k’s job… Even comment stripped it’s what? 5k?

    Mind you, a lot of the comments fall into the “Nuduuuh” category :P Seriously:

    //return the finished textfield HTML
    return textfield;

    No, REALLY?!? Might I suggest you take a quick read of:
    http://www.ibm.com/developerworks/linux/library/l-clear-code/

    Particularly the “and now we’re done” part.

    For improvements, first I’d make it NOT be doing getElementByID in the markup or need a ‘new’ object creation. You could just as easily pass the INPUT[password]‘s ID in to a function, and just have the function do a document.write; which would be a HELL of a lot simpler than all that DOM nonsense. (a lot less code too!)

    I would also make it dynamically change the label — if the javascript is working then it’s not a ‘show-password’ field, so perhaps the markup version should just say “password”?

    Really, all that needs to be done for compliant browsers to do what you are is to just “onchange” do a setAttribute(‘type’,’password’); or setAttribute(‘type’,’text’); as appropriate.

    Naturally that wouldn’t work in IE since type is ‘read only’, setattribute doesn’t work on input elements and it fires onclick instead of onchange (even when it’s the keyboard!). The best bet is to build a new DOM object and do parentNode.replaceChild after copying all the values over… but you could use a @cc_on to set a string value and a “document.write(‘<script src=" to sub-load the appropriate hander function… Would mean an extra handshake, but with the IE version being 500+ bytes all to itself, it's probably a wash on the handshake and it's not like javascript isn't cached across pages.

    Lemme see… coding… ok…

    Came up with this:
    http://www.cutcodedown.com/codeExamples/showPasswordCheckbox/demo.html

    I left the directory unlocked:
    http://www.cutcodedown.com/codeExamples/showPasswordCheckbox/

    For easy access to the bits and pieces. Redid the CSS (pulling all the CSS3 – no need to confuse matters) to have less cross-browser issues (did you see what your code did on LF/120dpi systems? Dunno who started that metricless line-height garbage but it doesn't work!)

    relies on three .js files:

    showPasswordCheckbox.js – 1,153 bytes – what the user loads in their HEAD contains the function they would call, as well as some variables they might like to modify.

    showPasswordCheckboxHandlerDOM.js – 347 bytes – the standards compliant check state function. The comment at the top is probably bigger than the code. This is what 'real' browsers get to use.

    showPasswordCheckboxHandlerIE.js – 861 bytes – The IE version which uses a DOM object creation and swap instead of just manipulating one DOM attribute. It's ridiculous you have to take it this far.

    Which totals just a hair over 2.3k… a very nice reduction/simplification, especially when IE users would be sent just under 2k, and standard compliant browser users would be sent less than 1.5k… and that's without compression. (though it's a wee bit light on the comments since I don't feel the need to comment EVERY line — that's what verbose variable names are for!)

    I'm going to cross-post this to the javascript section of the forums to invite others to further tweak the idea. More eyes on it the better a version we can come up with.

    Thinking on further improvements, it might be cute to expand it so all you have to do is include the javascript and let it do all the gruntwork… You could document.getElementsByTagName('input'), check for the password ones or see if they have a specific class defined, then auto-add everything. Would be a lot less markup and a lot cleaner a forms… I might take a stab at that as a 'take three'.

  • Tommy Carlier

    I’m not a fan of “Show password”, because my fingers know my passwords better than my eyes do. I mostly use random passwords that I never visualize. When I want to recall a password, I have to type it in because the “thinking”-part of my brain doesn’t know it: it seems as though my fingers have memorized the movements.

  • Dave

    Minor:
    You need to set the cursor style on the label tag for IE to display the regular arrow pointer vs. the text selector I bar.
    Major:
    I still don’t get why you need to use duplicate ID’s – just set the text one to:
    “{originalID}_display” and you’re done!
    Best of all, you aren’t mucking with invalid markup.
    Likewise browsers behave differently when you use getElementById(id) when there is more than one element. IIRC, all return the first match in the DOM,… except IE which returns the last match.
    see here: http://webbugtrack.blogspot.com/2008/06/bug-or-feature-round-three.html
    It’s just plain wrong – don’t do it!
    Otherwise nice example – the best usability for the end user – though I’m sure a quick 8 line jQuery addon would handle this more gracefully. ;-)

  • http://www.brothercake.com/ brothercake

    @deathshadow60 – okay a few things here.
    Firstly, you clearly have a very different coding style from me, and fair enough. In your approach, you avoid the “saggy midsection” as you put it – code which compensates for the usability issues exposed by the cross-browser approach I took. You don’t have those problems, so you don’t need that code, but there is a cost.

    You have a script which makes 2 HTTP requests, relies on a vendor-specific interpretation, has no error-handling or protection for legacy browsers, doesn’t cater for all the attributes that the field might have in IE, and fundamentally is built using a technique I can only describe as procedural hacking — document.write? Dude, are you from the past? innerHTML is bad enough.

    Nevertheless, I respect the fact that you’ve come up with a much simpler solution, even if it is an incomplete one.

    I have to admit that the solution I posted was actually adapted from a much larger library, that does a whole bunch of inter-dependent things, and I just extracted this functionality without stopping to consider whether there was a better way to write it from scratch. For that I apologise, but this post isn’t about the script, it’s about the concept.

    Still though, I would never ever build a script the way you have, it’s just not a clean or interoperable code style, and it pollutes the global scope.

    With regard to commenting — what you (and the article you linked to) fail to consider is that there’s another audience for code commenting, and that’s the educational audience. People who read it as part of learning the language, to help them understand how things work, and for those people it is extremely helpful to comment every single line, in explicit detail as I have. That’s why I write verbose over-descriptive comments – and if it seems all obvious to you, then clearly you’re not the audience.

    [Even putting that aside, the *primary* audience for code commenting is the programmer themselves. And if any given programmer likes to put "and we're done" at the end of their functions - or whatever - isn't it just academic sneering to say that's wrong?]

    @Dave – the point with the duplication of ID is the plain field will inherit most or all CSS rules that originally applied to the password field, without any explicit intervention. Maybe that’s an over-engineered solution, but it seemed like the simplest way at the time. But for the record – when getElementById finds more than one element with the same ID *all* browsers (including IE) return the first one – I tested this for the JavaScript Reference; what you linked to is incorrect.

  • Arkh

    “it would still be better if it were implemented by the browser itself” if only… it would have the added benefit of not having clear passwords saved to the input auto-fill history.

  • Chris White

    I thought of a better solution.

    What if we used AJAX to post the password via onchange to a page in PHP. It would return the value of the password field. Then we would have that value available in Javascript for any other technique we like.

    My initial idea would be to have a pop up or title tag that displays the text inside. You could of course expand that to a checkbox which prints the password onto the page as you go, or when the user requests it.

    • Chris White

      In fact, after testing it out just now. I found that you don’t even need to AJAX it because you can just grab the password from the value attribute with Javascript.

      If I attach an event to the password field and send it to another container, i can simply show or hide that container and it gives the user access to what they are writing. Unless there is a solid reason for having it as text in the input, i think this is a far simpler solution.

      Please feedback if there is something i should consider.

  • Jarmo Valmari

    I like the idea – we could get rid of re-enter password thingy that’s commonly in use.

    One comment. I’d rather have the controller a link than a checkbox. A checkbox it is used to give some specifics in a form to be sent on the server. This case it’s just about toggling visibility, not sending anything different so it goes against the very meaning of the checkbox. Also, a checkbox in a login form usually means “remember me”.

    Anyway, a technique to toggle visibility of the password should be available in registration forms to give users more control. It’s time to stop asking users to re-enter stuff in forms. That’s just like saying “you probably don’t know how to type in this particular field even though we do trust your skills in all the other fields.”

    Nokia (and later, iPhone) style masking doesn’t work for people who use more than one finger to type things and to be useful, that would slow down users with keyboards. It’s good for mobile phones, not for proper typing tools.

    By the way, Jakob Nielsen has reported that users have problems with masking the password.

    Now, a shameless ad (:D). You can find more ux/usability-related opinions on matters like this here: http://uxbuzz.blogspot.com