jQuery Password Mask - DIY

July 17, 2009

I was reading Jakob Nielsen's post Stop Password Masking, which is an interesting read. I like the idea of letting the user decide if they want to be able to see their password or have it masked. There are several jQuery plugins out there which do the job, some of are really clever and mask the password as you type (like mobile phones do).

Then the developer in me kicked in and I decided I should try to write the code myself. I thought I'd post it here to show how the power of jQuery lets you do something like this quite easily.


<html>
<head>
<script type="text/javascript"
src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js">

</script>
<script type="text/javascript">
$(function(){
  $('<a href="#" class="passwordmask">show password</a>')
  .insertAfter($('input[type=password]'))
  .click(function(){
      $password = $(this).prev();
      $clone = $password.clone();
      if ($password.attr('type')=='password')
      {
        $clone.attr('type','text');
        $(this).text('hide password');
      }
      else
      {
        $clone.attr('type','password');
        $(this).text('show password');
      }
      $clone.insertAfter($password);
      $password.remove();
      return false;
    });
});
</script>
</head>
<body>

<form>
<input type="text" id="username" name="username" value="username" /><br />
<input type="password" id="password" name="password" value="my-password" /><br />
<input type="submit" id="submit" name="submit" value="login" />
</form>

</body>
</html>

I'm not saying that my code is better than the plugins, I'm sure that this could be refined and improved but it does the job. I just think it's worth learning how to do things in jQuery even if I decide to to use a plugin in my production code.

If you want to know about jQuery then there is a section on the jQuery site for tutorials, I also recommend checking out 40+ Excellent jQuery Tutorials. There is also a sample chapter from the Learning jQuery 1.3 book on the which you can download for free.

Update!

Julian Halliwell pointed out to me that the web developer's favourite browser, Internet Explorer, won't let you change the type attribute. I wanted to add a few features to my code so here is a new version which:

Anyway, here is the updated version.


<html>
<head>
<script type="text/javascript"
src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js">

</script>
<script type="text/javascript">
$(function(){
// assign a class to all password boxes to make it easy to select
$('input[type=password]').addClass('passwordfield');
// create a link after the first password field in the form
// and assign a click event to it
$('<a href="#" class="passwordmask">show password</a>')
.insertAfter($('form').find('input[type=password]:eq(0)'))
.click(function(){
// create a reference to the clicked link
$clicked = $(this);
// find the form this link is in
$parentform = $clicked.parents('form')
.find('input.passwordfield')
.each(function(i,el){
// create a reference to the password field
$password = $(el);
// IE doesn't support changing the type attribute
// so create a new element (hat tip to Julian Halliwell)
if ($password.attr('type')=='password')
{
$clone = $('<input type="text" />');
$clicked.text('hide password');
}
else
{
$clone = $('<input type="password" />');
$clicked.text('show password');
}
// copy all attributes to clone
var attrs = $password[0].attributes;
// IE throws errors if you try to set type, value or dataFormatAs attributes
if (attrs[i].nodeName!='type'&&attrs[i].nodeName!='value'&&attrs[i].nodeName!='dataFormatAs'){
$clone.attr(attrs[i].nodeName, $password.attr(attrs[i].nodeName));
}
// set required attributes
     $clone.attr('class',$password.attr('class'));
$clone.attr('name',$password.attr('name'));
$clone.attr('id',$password.attr('id'));
// set the value
$clone.val($password.val());
// insert clone after the current password box
$clone.insertAfter($password);
// remove the current password box
$password.remove();
})
.end()
.submit(function(){
$theform = $(this);
if($theform.find('input[type=password]').size()==0){
// paswords visible!
$theform.find('.passwordmask').click();
}
return true;
});
return false;
});
});
</script>
</head>
<body>

<form id="form-one">
<label for="username">Username:</label><br />
<input type="text" id="username" name="username" value="username" /><br />
<label for="password">Password</label><br />
<input type="password" id="password" name="password" value="my-password" /><br />
<label for="password">Confirm Password</label><br />
<input type="password" id="passwordconfirm" name="passwordconfirm" value="my-password" /><br />
<input type="submit" id="submit" name="submit" value="login" />
</form>

<form id="form-two">
<label for="username_2">Username:</label><br />
<input type="text" id="username_2" name="username_2" value="username" /><br />
<label for="password_2">Password</label><br />
<input type="password" id="password_2" name="password_2" value="my-password" /><br />
<label for="password_2">Confirm Password</label><br />
<input type="password" id="passwordconfirm_2" name="passwordconfirm_2" value="my-password" /><br />
<input type="submit" id="submit_2" name="submit_2" value="login" />
</form>

</body>
</html>

 


10 comments

  1. Hi John, I think this is a good option to offer, as long as it is just an option, and not the default. Glad to see you've done it that way.

    There is a problem with your implementation though: it won't work in IE because the type of an existing input element can't be changed.

    The plugin you linked to gets round this by creating a new text input and synching the values with the password input. I found the code a little opaque so like you I decided to write my own:

    simplicityweb.co.uk/code/showpassword/ />
    Cheers
    Julian.

    Comment by
    Julian Halliwell – July 18, 2009
  2. Hi Julian, thanks for the heads up, it's a shame as using clone() is so much easier! Anyway I've updated my post to handle this and added some extra functionality that I wanted. You've gotta love IE :P

    Comment by John Whish – July 19, 2009
  3. Works, but lost my 'id' attribute when toggling.

    Added a new line :

    // copy the class
    $clone.attr('class',$password.attr('class'));

    becomes :

    // copy the class
    $clone.attr('class',$password.attr('class'));
    $clone.attr('id',$password.attr('id'));

    .. and now works great!

    Thanks!

    Comment by Red Carrot Web Design – October 20, 2009
  4. Dammit!

    After using this code my submit button no longer works.

    Thanks anyway...

    Comment by Red Carrot Web Design – October 20, 2009
  5. @redcarrot, yeah realised the code I posted returns false inside the submit(function(){}) call which I did whilst testing. Should be return true!

    Comment by John Whish – October 20, 2009
  6. Thanks for that.

    The submit button works once again, but I have a new problem.

    If I have a value in the field, and toggle, the field submitted is empty.

    If I don't toggle, the field is not empty.

    I really want this to work. I've tried a few plugins, but your code seems to come closest to working.

    Comment by Red Carrot Web Design – October 20, 2009
  7. @redcarrot Try, doing this:

    // copy the class   $clone.attr('class',$password.attr('class'));
    $clone.attr('id',$password.attr('id'));
    $clone.attr('name',$password.attr('name'));

    Form fields are passed back by name not id

    Comment by John Whish – October 20, 2009
  8. Thanks - works fine now.

    The 'id' thing was a seperate issue - my 'id' was required for the form styling, so when I clicked 'show password' my input box would shrink!

    With your fix, the 'name' attribute is always present, and so the form submits just fine.

    Here is the full fix :

    // copy the class
    $clone.attr('class',$password.attr('class'));

    changes to ...

    // copy the class
    $clone.attr('class',$password.attr('class'));
    // copy the id
    $clone.attr('id',$password.attr('id'));
    // copy the name
    $clone.attr('name',$password.attr('name'));

    Thank you for your help!

    Comment by Red Carrot Web Design – October 21, 2009
  9. @Julian Halliwell:
    Your script has no effect in FF3.5.5 !?

    @John:
    Thanks for this post - really!
    I'll have to think about it for a while...

    Comment by jQuery Agentur – November 17, 2009
  10. I can't find the demo link :(

    Comment by Colin – February 02, 2010

Leave a comment

If you found this post useful, interesting or just plain wrong, let me know - I like feedback :)

Please note: If you haven't commented before, then your comments will be moderated before they are displayed.