One of the more annoying aspects of having to remember passwords (along with having to remember loads of them) is that if you’ve got Caps Lock turned on accidentally when you type one in, it won’t work, and you won’t know why. Most desktop computers alert you in some way if you’re trying to enter your password to log on and you’ve enabled Caps Lock; there’s no reason why the web can’t do the same. What we want is a warning – maybe the user wants Caps Lock on, because maybe their password is in capitals – rather than something that interrupts what they’re doing. Something subtle.
But that doesn’t answer the question of how to do it. Sadly, there’s no way of actually detecting whether Caps Lock is on directly. However, there’s a simple work-around; if the user presses a key, and it’s a capital letter, and they don’t have the Shift key depressed, why then they must have Caps Lock on! Simple.
DOM scripting allows your code to be notified when a key is pressed in an element; when the key is pressed, you get the ASCII code for that key. Capital letters, A to Z, have ASCII codes 65 to 90. So, the code would look something like:
on a key pressif the ASCII code for the key is between 65 and 90 *and* if shift is pressedwarn the user that they have Caps Lock on, but let them carry onend ifend keypress- Source: /code/capturing-caps-lock/1.txt
The actual JavaScript for this is more complicated, because both event handling and keypress information differ across browsers. Your event handling functions are passed an event object, except in Internet Explorer where you use the global event object; the event object has a which parameter containing the ASCII code for the key pressed, except in Internet Explorer where the event object has a keyCode parameter; some browsers store whether the shift key is pressed in a shiftKey parameter and some in a modifiers parameter. All this boils down to code that looks something like this:
keypress: function(e) {var ev = e ? e : window.event;if (!ev) {return;}var targ = ev.target ? ev.target : ev.srcElement;// get key pressedvar which = -1;if (ev.which) {which = ev.which;} else if (ev.keyCode) {which = ev.keyCode;}// get shift statusvar shift_status = false;if (ev.shiftKey) {shift_status = ev.shiftKey;} else if (ev.modifiers) {shift_status = !!(ev.modifiers & 4);}// At this point, you have the ASCII code in "which",// and shift_status is true if the shift key is pressed}- Source: /code/capturing-caps-lock/2.txt
Then it’s just a check to see if the ASCII code is between 65 and 90 and the shift key is pressed. (You also need to do the same work if the ASCII code is between 97 (a) and 122 (z) and the shift key is not pressed, because shifted letters are lower-case if Caps Lock is on.)
if (((which >= 65 && which <= 90) && !shift_status) ||((which >= 97 && which <= 122) && shift_status)) {// uppercase, no shift key/* SHOW THE WARNING HERE */} else {/* HIDE THE WARNING HERE */}- Source: /code/capturing-caps-lock/3.txt
The warning can be implemented in many different ways: highlight the password field that the user is typing into, show a tooltip, display text next to the field. For simplicity, this code shows the warning as a previously created image, with appropriate alt text. Showing the warning means creating a new <img> tag with DOM scripting, dropping it into the page, and positioning it so that it’s next to the appropriate field. The image looks like this:

You know the position of the field the user is typing into (from its offsetTop and offsetLeft properties) and how wide it is (from its offsetWidth properties), so use createElement to make the new img element, and then absolutely position it with style properties so that it appears in the appropriate place (near to the text field).
The image is a transparent PNG with an alpha channel, so that the drop shadow appears nicely over whatever else is on the page. Because Internet Explorer version 6 and below doesn’t handle transparent PNGs correctly, you need to use the AlphaImageLoader technique to make the image appear correctly.
newimage = document.createElement('img');newimage.src = "http://farm3.static.flickr.com/2145/2067574980_3ddd405905_o_d.png";newimage.style.position = "absolute";newimage.style.top = (targ.offsetTop - 73) + "px";newimage.style.left = (targ.offsetLeft + targ.offsetWidth - 5) + "px";newimage.style.zIndex = "999";newimage.setAttribute("alt", "Warning: Caps Lock is on");if (newimage.runtimeStyle) {// PNG transparency for IEnewimage.runtimeStyle.filter += "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://farm3.static.flickr.com/2145/2067574980_3ddd405905_o_d.png',sizingMethod='scale')";}document.body.appendChild(newimage);- Source: /code/capturing-caps-lock/4.txt
Note that the alt text on the image is also correctly set. Next, all these parts need to be pulled together. On page load, identify all the password fields on the page, and attach a keypress handler to each. (This only needs to be done for password fields because the user can see if Caps Lock is on in ordinary text fields.)
var inps = document.getElementsByTagName("input");for (var i=0, l=inps.length; i- Source: /code/capturing-caps-lock/5.txt
The “create an image” code from above should only be run if the image is not already showing, so instead of creating a newimage object, create the image and attach it to the password field so that it can be checked for later (and not shown if it’s already showing). For safety, all the code should be wrapped up in its own object, so that its functions don’t collide with anyone else’s functions. So, create a single object called capslock and make all the functions be named methods of the object:
var capslock = {...keypress: function(e) {}...}- Source: /code/capturing-caps-lock/6.txt
Also, the “create an image” code is saved into its own named function, show_warning(), and the converse “remove the image” code into hide_warning(). This has the advantage that developers can include the JavaScript library that has been written here, but override what actually happens with their own code, using something like:
<script src="jscapslock.js" type="text/javascript"></script><script type="text/javascript">capslock.show_warning(target) {// do something different here to warn the user}capslock.hide_warning(target) {// hide the warning that we created in show_warning() above}</script>- Source: /code/capturing-caps-lock/7.txt
And that’s all. Simply include the JavaScript library in your pages, override what happens on a warning if that’s more appropriate for what you’re doing, and that’s all you need.


Comments
Got something to add? You can just leave a comment.
04/12/2007
It’s a great idea and works almost. My Safari 3 and Firefox 2.0.0.11 reports the same keyCode when caps lock is on, no matter if shift is pressed or not. This makes the script works great if you don’t have Caps lock on and use shift at the same time.
04/12/2007
Very cool and inventive technique. However, there has to be a way to do this without first requiring a user to enter a letter. Otherwise, a certain amount of nice functionality is lost.
For instance, whenever entering a password in Mac OS X and you have the Caps Lock key on a cool little up arrow shows up in the field. Is there a method of detecting before a user enters anything (and then applying some CSS class, etc.)
I know it is possible with IE, but I think it would be best to find some cross browser method. http://concepts.waetech.com/caps_lock/
04/12/2007
Now this is what I call thinking outside the box! This is a great usability trick.
Thanks for the great article Stuart, I will be using this in future projects.
04/12/2007
Great!
I love these little usability enhancements. You have certainly done some nice hacking, thanks a lot.
04/12/2007
A neat idea but falls down in some cases because of the assumption on the nature of keyboard operation. Some keyboards – definitely the iPhone and I suspect also assistive techniques such as Sticky Keys on Windows – let you type capitals without enabling caps lock or holding down shift so the assumption fails.
For the iPhone you could include an exception based on the user-agent. But clearly that won’t capture all such quirky keyboards.
04/12/2007
Nevermind that I could have figured this out on my own, but I sure as hell wouldn’t have thought of it… this is a genius usability enhancement to any password form! I can’t think of how many times I’ve retyped in a password over and over ‘thinking’ I’m typing it correctly, only to find out I had caplocks on.
Well done.
04/12/2007
How well does this work for non-English locales? It looks like it won’t display the caps lock warning if the user enters an accented letter. I wonder what happens in non-latin locales?
04/12/2007
Can someone please make a greasemonkey script that uses this? It’d be worth its weight in gold.
04/12/2007
Hey Arthus,
I would just add an event listener for focus on the input. Could be possible to attach a listener to the window load as well, etc.
04/12/2007
I’ll guesstimate that 10-20% of casual users use caps lock for single characters in stead of shift when entering passwords after observing hundreds of university students enter their passwords working as first line support.
05/12/2007
James: hand on heart, I’m not sure. I did consider the issue of non-English locales, but I don’t know enough about what happens if you capitalise a non-English letter. I’d love to hear commentary from people who know about this so that the script can correctly handle those characters!
06/12/2007
As possibly mentioned above, this isn’t true on the Mac. I don’t think that matters though: I can’t imagine many people putting caps lock on, then holding down shift when they type letters.
21/01/2009
Hey, this should work for accented letters.
var char = string.fromCharCode(which);
if(char.toLowerCase() == char) var is_lower_case = true;
if(char.toUpperCase() == char) var is_upper_case = true;
11/06/2009
Anyone have an idea why this doesn’t work in a <td> form element?
18/08/2009
good but will not work with IE6. any fix out there?
Impress us