Better Passwords #2: “Show Password”
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:
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
"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
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
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.
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.
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!!
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