jQuery Plugin Development: Hover to Reveal Masked Password

Posted in Coding, HTML & CSS, JS & AJAX • Posted on 17 Comments

We talked about how to improve your HTML forms performance a couple of days ago. There we covered a pretty controversial topic “Don’t mask your passwords”, discussing how bad masking your passwords could be for usability.

At this moment, we basically have two options: mask password field and don’t ask for any feedback, or show password field as text and potentially decrease security.

This is why I think a hover revealing password could be a really good alternative: You can increase your security, and if you are unsure about what you’ve typed just go and hover over it.

So, what we will be doing today is a jQuery plugin to do that, and additionally, we will have a behavior pretty similar to what many mobiles does, where we can see the last character for a couple of seconds. This is a good chance to learn more about plugins, dynamically generated content, and some good coding practices.

Moreover with this technique we could apply different effects and a lot of variations since all this things are based on non-obtrusive and almost only decorative javascript.

So, let’s rock!

Demo, download and preview

Let’s begin with the best part. You can see our working demo or download our files and jQuery plugin.

Usability background

Before any coding I think it’s important to know why are we doing all these things. It is all about user experience and to make things the best they can be.

The man who started discussing masked passwords (as far as I know) is Jakob Nielsen, with his extremist opinion expressed in  stop password masking article. But I really think we don’t need to stick with just two options. I think we can improve all these techniques, like what mobile developers have done, improving user experience by creating a “new” way to input password data.

Don’t get me wrong, sometimes we do need to just keep masking passwords for security reasons. You know, sometimes we are near suspicious people or jealous girlfriends just waiting for a single mistake to steal our password and make big damage to our online life. But sometimes we don’t. I mean, we don’t need to let our software ready only for the worst case.

We have to be ready for the worst and the best. From IE6 (argh!) to Chrome 14.0.803.2 beta. From jealous girlfriends to hurried surfers. This is the tricky part, trying to be the best in most cases.

This is why we can’t just let passwords to be masked by default. We have to give a better option to our loyal users.

Getting started

What we will do here is to get a common password field, change it to text and create a mask above it, which is filled as you type. With this you can do anything with the “mask” without affecting the input content itself.

Maybe this image will better explain how it works:

Well, finally, let’s get started on coding.

We will start with a pretty basic form markup. As you all know it’s quite simple, so let’s add two fields, one that should come with a default value and another in blank, for you to play with as you want.

<div id="container">
	<h1>Sign Up!</h1>
	<form action="#" method="get">
		<label>
			<span class="title">Old Password</span>
			<span class="desc">This is our awesome password field with default value. Try it out!</span>
			<input type="text" name="oldpassword" id="oldpassword" value="tHis1$myP4swrd." />
		</label>
		<label>
			<span class="title">Password</span>
			<span class="desc">This is our awesome blank password field. Try it out!</span>
			<input type="password" name="password" id="password" />
		</label>
	</form>
</div>

Ok, then we need to call our magic jQuery and plugin files. Let’s do that:

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"> // call jQuery from google! </script>
	<script type="text/javascript" src="jquery.hp.js"> // call plugin </script>

Well, let’s create our basic plugin file. You can see some tips about it in our jQuery Smooth Table of Contents Plugin, where we have a really simple structure.

(function($){
 $.fn.hoverpass = function(options) {
	//Our default options
	var defaults = {
		bullet: "&bull;", //which should be the "masking" character
		font: "'Lucida Console', monospace", //please just use MONOSPACE fonts
		bg: "#fff", // background style for bullets
		free: "", // add your own additional styling here
		freeBul: "float: left; overflow: hidden;", // add your own additional styling for bullets here
		delay: 500, //how long it takes to create the bullet over the last character, in milliseconds
		delayHover: 3000, //how long it takes to hide again a hovered character
		animation: 500, //how long it takes the animation itself
		maxSize: 10 // maximum number of characters, to prevent  bullets exploding input's size
	};

	//let's extend our plugin with default or user options when defined
	var options = $.extend(defaults, options);

    return this.each(function() {
		//our action goes here
    });
 };
})(jQuery);

Above we defined our default variables, let me explain some of them a little bit:

  • bullet – Is what will mask our password. You can use any character but use just one character or HTML entity.
  • font – This is really important, this plugin only works with monospaced fonts. Since in other types, each character has his own width, we can’t “mask” it.
  • bg - If you use any background in your input, then you should apply it to your mask too, since it will be above the input.
  • free - Here you should add margins in order to compensate any padding that your input has. Furthermore you should set your input’s font-size here.
  • maxSize – This is important if your password field is too short. If you don’t adjust it you may get some extra bullets exploding your input’s size.

At this point you have a basic plugin, that is called via $(elem).hoverpass(), defined by our second line $.fn.hoverpass = function(){}.
I know, this name sucks. I would be glad if you send suggestions about better names :).

Change our input type to text

I don’t know if you’ve tried this before, but let me tell you something, you just can’t change the type of inputs. This happens due to security reasons, right? Well, seems that just IE will worry about it (you can do it via old JavaScript in real browsers). Anyway, what we have to do then is create a “clone” of current input without type property.
There is several ways of doing this, I’ve done it this way:

return this.each(function() {
	//let's declare some variables, many as a "shortcut" for options
	var  bullet = options.bullet,
			font = options.font,
			bg = options.bg,
			free = options.free,
			freeBul = options.freeBul,
			delay = options.delay,
			delayHover = options.delayHover,
			animation = options.animation,
			lastBul = "";

	//since we just can't change a field's type, we'll remove it and append a brand new text input on it's place
	var oldElement = $(this); // caching element, much better performance
	var inputHTML = '<input type="text" style="font-family: '+  font +'; " />'; //this is our basic input text, with our monopace font
	var input = oldElement.after(inputHTML).next(); //appending our simple text field with our styling (font-family) AND caching it as var "input"

	/****
		we are saying here:
			define the following variables: attr , i (zero), attrs (array with all oldElement attributes), l (size of attrs)
			while our counter (i) is smaller than attributes lenght (l) increase our counter and run this code
	*/
	for ( var attr, i=0 , attrs = oldElement[0].attributes , l =attrs.length ; i < l ; i++){
		attr = attrs.item(i)
		if (attr.nodeName != "type" && attr.nodeName != "style") { //well, we defined our type as text and font-style!
			input.attr( attr.nodeName, attr.nodeValue );
		}
	}
	oldElement.remove(); // bye, bye input type="password"!
});

Create our mask and bullets

Wow, at this point, when you define $(elem).hoverpass() it will turn into a monospaced text input. Pretty cool, huh? But we want more than this.

Now we will create our bullets container. The only really interesting thing in this two lines is that jQuery element caching again. You really should be using this simple technique:

	// let the game begin
	var maskHTML = '<div class="hpMask" style="position: absolute; cursor: text; height: 1px; font-family: ' +  font + ' ; ' + free + ' " />'; //our container with his styling
	var maskContainer = input.before(maskHTML).prev(); // appending our container for bullets with styling (font-family, free)

Now we’ll prepare our bullets HTML, since it will be used several times, and add some bullets when we have a “value” attribute defined.

	var bulletHTML = "<span class='hpBullet' style='background: " + bg + "; " + freeBul + " '>"+ bullet + " </span> "; // our bullets HTML with styling (bg, freeBul)
	var countBullet = 0; // this is our counter, it is important to prevent our mask to get bigger / smaller than our input or its maximum size

	//since we use it from different places, it's better to add it via function
	function addBullet() {
		// add our last bullet, but hidden, and show anything that isn't last bullet
		lastBul = maskContainer.append(bulletHTML).find(":last-child").hide();
		maskContainer.find(":not(:last-child)").each( function(){ $(this).show();  } );
		//start timer to show  lastBul
		lastBul.delay(delay).fadeIn(animation);
		countBullet++;
	}

	//first loop adding bullets when we have a default value
	for ( i=0 ; i < input[0].value.length ; i++){
		addBullet();
	}

Well, at this point you should see again a textfield but if you have a value attribute defined, you’ll see a lot of bullets and the last one fading after one second. Although, if you type, nothing happens.

It’s time to play with keyboard

No, we won’t be taking music classes here :)

We now need to append new bullets every time something is typed in our password field, and remove one bullet if the pressed character is delete or backspace.

We could do this via keypress, keyup or keydown.

Thinking about it a little bit with keydown and keypress (they are very similar) we bind “pressing key” and with keyup we bind “releasing key”. Looking a little closer, you might notice that in our case it means that keydown/keypress is called before we have any change in our field’s value but keyup is called after any change occurs.

This is why we need to use keyup here. We have to look at our field’s value and see “hey, have you changed your size?” in order to append or remove bullets. This is because we could have several scenarios when user selects part of the password, press delete in the beginning of the field and much other things that would be too painful to bind as separated actions.

So, let’s do it:

//let's bind all keydown and create / remove our bullets ; we need do use keydown in order to detect special characters in non-gecko browsers
	input.keyup(
		function(event) {
			//check if something was really typed
			if (input[0].value.length > countBullet) {
				addBullet();
			} else { //ooops, delete or backspace?
				//then we check if something was really deleted
				while (input[0].value.length < countBullet) {
					maskContainer.find(":last-child").remove();
					countBullet--;
				}
			}
		}
	);

Finally, hover-revealing field!

Well, now we just have to hide our bullet when someone hovers it. Kind of easy, right? Well, it isn’t that easy. It is because we have to hide our bullet, but we can’t lose it’s width, because if we do, our users would see only the last character of the password (not the ones in the middle). What we can do is to fade it to an insignificant opacity (like 10%) and then change it’s height to 1px, so we still have width.

Ok, now it’s just to use elem.hover() and we’re done, right? Again, no. This is because we have dynamically generated content we should use live() or delegate() to bind it. In my tests delegate had a much better performance, so we will do it this way:

//hide bullets based on a jquery object
	function hideBullets(object) {
		object.stop().css({ "height": "auto"}).animate({ opacity: 1 }, animation).removeClass("hpHiddenBullet");
	}
	//hover function for our bullets
	maskContainer.delegate(".hpBullet",  'hover',
		function(){
			var item = $(this);
			if (  item.hasClass("hpHiddenBullet") != true ) {
				hideBullets( $(".hpHiddenBullet") );
				item.stop().addClass("hpHiddenBullet").animate( { opacity: 0.01}, animation, function() { item.css({ "height": "1px"}); } );
				setTimeout( function() {
					if (  item.hasClass("hpHiddenBullet") == true ) {
						hideBullets( item );
					}
				}, delayHover);
			}
		}
	);

Are you hungry yet?

Wow, hope you guys liked it. Maybe you’re not going to use this effect itself but I’m sure we have a lot of good snippets here that are worth using in other cases.

Talking about the final effect, what do you think about it? Have you seen a better alternative?

Show us your opinion and let’s find what could be the very best implementation to our users!

43 Written ArticlesWebsiteGoogle+

I'm a web designer and entrepreneur from Itajubá (MG), Brasil. I love writing about obscure topics and doing some cool stuff. And also I do some FREE stuff, check it out: http://www.roch.com.br/

17 Comments Best Comments First
  • San

    Sunday, July 24th, 2011 14:59

    1

    The problem with masking passwords is not the masking per se. It’s the inability to distinguish between the black dots and inability to check what you typed. This was my response to Nielsen back in June 2009. http://ow.ly/1uVOWB

    0
    • Rochester Oliveira

      Monday, July 25th, 2011 18:40

      4

      Hey San, isn’t this what I was talking about?

      []’s

      0
  • John

    Monday, July 25th, 2011 21:44

    7

    This is a pretty cool feature. Many people are used to a masked password but a lot of them type a wrong character during the sign up so they cannot login in the future. This hover function solves this problem. Thanks for the share Rochester Oliveira.

    0
    • Rochester Oliveira

      Tuesday, July 26th, 2011 05:25

      9

      Hi John!

      I’m glad you liked it, and I agree with you, it is specially useful in sign up forms.

      Thank you!
      []’s

      0
  • Theo

    Sunday, July 24th, 2011 22:43

    2

    Love this aproach, and even if @San pointed something similar back in 2009 you still deserve kudos for the code, thanks!

    0
  • Zeno Rocha

    Monday, July 25th, 2011 13:17

    3

    You should take a look at jQuery Boilerplate – http://jqueryboilerplate.com

    It’s a nice tip for your readers who want to create jQuery plugins.

    0
    • Rochester Oliveira

      Monday, July 25th, 2011 18:42

      6

      Hi Zeno, nice point. I’ll check it out, maybe it can be useful in our next plugin development tutorials!

      []’s

      0
      • Rochester Oliveira

        Tuesday, July 26th, 2011 05:37

        10

        Ah, sobre parecer um americano, muito obrigado! Mas ainda tem muito o que melhorar aí nessa minha escrita hehe Mas vamos melhorando um pouco de cada vez :)
        []’s

        0
      • Rochester Oliveira

        Tuesday, July 26th, 2011 05:23

        8

        Caramba, você também é brasileiro? Haha

        Vou testar ele em um tutorial de jogo em HTML + JS, já estou com a mecanca basica pronta, entao é só usar ele pra organizar melhor o plugin…

        Se não for ao ar nessa semana, deve ir já semana que vem. Mas de qualquer forma eu te aviso pelo contato do seu site!

        []’s

        0
  • Osvald

    Thursday, December 8th, 2011 15:55

    17

    We talked about how to improve your HTML forms performance a couple of days ago. There we covered a pretty controversial topic “Don’t mask your passwords”, discussing how bad masking your passwords could be for usability. At this moment, we basically have two options: mask password field and don’t ask for any feedback, or show.

    0
  • Ali

    Tuesday, September 20th, 2011 19:21

    15

    download & demo links are not working at the moment

    0
    • Rean John Uehara

      Tuesday, September 20th, 2011 20:57

      16

      Oh my, thank you for telling! It’s all fixed now! Thanks! :D

      0
  • Paul

    Wednesday, July 27th, 2011 23:56

    11

    Amazing! This is a rather innovative feature, and should fix the burdensome act of typing passwords out again for accuracy!

    0
    • Rochester Oliveira

      Thursday, July 28th, 2011 17:32

      12

      Hey Paul, thank you!

      I’m glad you liked it.

      []’s

      0
  • Sohail

    Wednesday, August 17th, 2011 18:56

    13

    I like it, when it comes to jQuery

    0
  • Osvald

    Thursday, December 8th, 2011 15:55

    17

    We talked about how to improve your HTML forms performance a couple of days ago. There we covered a pretty controversial topic “Don’t mask your passwords”, discussing how bad masking your passwords could be for usability. At this moment, we basically have two options: mask password field and don’t ask for any feedback, or show.

    0
  • Ali

    Tuesday, September 20th, 2011 19:21

    15

    download & demo links are not working at the moment

    0
    • Rean John Uehara

      Tuesday, September 20th, 2011 20:57

      16

      Oh my, thank you for telling! It’s all fixed now! Thanks! :D

      0
  • Sohail

    Wednesday, August 17th, 2011 18:56

    13

    I like it, when it comes to jQuery

    0
  • Paul

    Wednesday, July 27th, 2011 23:56

    11

    Amazing! This is a rather innovative feature, and should fix the burdensome act of typing passwords out again for accuracy!

    0
    • Rochester Oliveira

      Thursday, July 28th, 2011 17:32

      12

      Hey Paul, thank you!

      I’m glad you liked it.

      []’s

      0
  • John

    Monday, July 25th, 2011 21:44

    7

    This is a pretty cool feature. Many people are used to a masked password but a lot of them type a wrong character during the sign up so they cannot login in the future. This hover function solves this problem. Thanks for the share Rochester Oliveira.

    0
    • Rochester Oliveira

      Tuesday, July 26th, 2011 05:25

      9

      Hi John!

      I’m glad you liked it, and I agree with you, it is specially useful in sign up forms.

      Thank you!
      []’s

      0
  • Zeno Rocha

    Monday, July 25th, 2011 13:17

    3

    You should take a look at jQuery Boilerplate – http://jqueryboilerplate.com

    It’s a nice tip for your readers who want to create jQuery plugins.

    0
    • Rochester Oliveira

      Monday, July 25th, 2011 18:42

      6

      Hi Zeno, nice point. I’ll check it out, maybe it can be useful in our next plugin development tutorials!

      []’s

      0
      • Rochester Oliveira

        Tuesday, July 26th, 2011 05:23

        8

        Caramba, você também é brasileiro? Haha

        Vou testar ele em um tutorial de jogo em HTML + JS, já estou com a mecanca basica pronta, entao é só usar ele pra organizar melhor o plugin…

        Se não for ao ar nessa semana, deve ir já semana que vem. Mas de qualquer forma eu te aviso pelo contato do seu site!

        []’s

        0
      • Rochester Oliveira

        Tuesday, July 26th, 2011 05:37

        10

        Ah, sobre parecer um americano, muito obrigado! Mas ainda tem muito o que melhorar aí nessa minha escrita hehe Mas vamos melhorando um pouco de cada vez :)
        []’s

        0
  • Theo

    Sunday, July 24th, 2011 22:43

    2

    Love this aproach, and even if @San pointed something similar back in 2009 you still deserve kudos for the code, thanks!

    0
  • San

    Sunday, July 24th, 2011 14:59

    1

    The problem with masking passwords is not the masking per se. It’s the inability to distinguish between the black dots and inability to check what you typed. This was my response to Nielsen back in June 2009. http://ow.ly/1uVOWB

    0
    • Rochester Oliveira

      Monday, July 25th, 2011 18:40

      4

      Hey San, isn’t this what I was talking about?

      []’s

      0

Comments are closed.

54.167.173.250 - unknown - unknown - US