Simple Tricks for More Usable Forms

Web developers loathe the task of building forms almost as much as users loathe having to fill them in. These are both unfortunate facts of the Web, but some smart JavaScript and intelligent CSS can go a long way to remedying the situation. In this article, I’ll introduce a number of simple tricks for improving the usability of forms, and hopefully inspire you to improve on them and create your own.

I’m going to start off with some simple tricks, before introducing the interesting stuff later on. If the material seems too simple for you, feel free to skip ahead.

It’s the Little Things that Count

You will certainly have encountered our first trick before; it’s used by Google, the world’s most popular search engine. Whenever you load up www.google.com, your cursor jumps straight to the search box, ready for you to enter your query. It happens so fast you may not even have thought about it, but, in fact, it works equally well in any situation in which the primary purpose of a page is to fill in a form. It can be done in a number of different ways, each of which assumes that the form element you want to focus on has an id attribute set to "myfield":

<body onload="document.getElementById('myfield').focus()">

This is, more or less, the method used by Google. It’s short and to the point. It does, however, require the addition of an onload to your body element, which some people find unsightly.

<script type="text/javascript"> 
window.onload = document.getElementById('myfield').focus;
</script>

This can be added to any point in your HTML file, or hidden away in an external script. If you’re going to be using a lot of JavaScript on a page, it can make sense to move it all in to an external script file in order to keep the JavaScript code separate from your HTML. This method has the disadvantage that you can only assign one thing to the window.onload event at a time.

<script type="text/javascript"> 
addEvent(window, 'load', function() {
 document.getElementById('myfield').focus()
});

function addEvent(obj, evType, fn){
 if (obj.addEventListener){
    obj.addEventListener(evType, fn, true);
    return true;
 } else if (obj.attachEvent){
    var r = obj.attachEvent("on"+evType, fn);
    return r;
 } else {
    return false;
 }
}
</script>

This uses Scott Andrew’s addEvent function, which I discussed in my previous article. This is probably the best approach to take if you’re keeping your code in a separate file, as it will allow other functions to be attached to the onload event as well.

<script type="text/javascript"> 
document.getElementById('myfield').focus();
</script>

The above will only work if it is placed in the HTML source code some point after the input field. This can be useful if you are working with a server side templating system that makes it difficult to add code directly to the top of a document — for example, if you are including the top part of the page using a server side include.

The above four options are available for most of the tricks I’ll demonstrate in this article. For future tricks, I’ll demonstrate the method using inline attributes such as onload and onclick only, but you should be aware that there are several ways to skin this particular cat.

Labels

The quickest way to enhance your form usability is to add labels, if you’re not using them already. The <label> element has been part of HTML since 1998, but many developers remain unaware of its existence. It allows you to logically relate the text describing a form field to the form field itself. When the user clicks on the label, the browser will move the focus to the related form field, or toggle its state in the case of radio boxes and check buttons. Before you add a label, the form field must have an ID attribute set. In fact, the tips in this article almost all require an ID attribute be set on the form field, as this provides a useful means of targeting that field from JavaScript.

Here’s the simplest example of a label in action:

<label for="username">Username:</label>  
<input type="text" name="username" id="username" size="10">

Clicking on the word "Username" will focus the cursor in the text box. This may not seem like a particularly useful effect, but it gives us a useful hook for styling and potentially adding extra JavaScript behaviour. It also dramatically improves the accessibility of the form for users of assistive software.

Where labels really come in to their own is with checkboxes and radio boxes. Both these widgets are plagued by a tiny active area, sometimes called a "hotspot", which you need to hit dead on with your mouse to cause them to toggle. Adding a label increases the hotspot to cover the text associated with the widget as well:

<input type="checkbox" name="accepted" id="accepted">  
<label for="accepted">I agree to the terms and conditions</label>

Of course, labels aren’t much good if people don’t know they’re there. One simple but effective trick for increasing the visibility of labels is to use CSS to change the cursor over them:

<style type="text/css">  
label {  
 cursor: pointer;  
 cursor: hand;  
}  
</style>

Why the two cursor declarations? The CSS standard dictates "pointer" as the value for a "pointer that indicates a link". Unfortunately, IE 5 and IE 5.5 for Windows don’t understand this value, using "hand" to mean the same thing. By placing pointer first misbehaving Microsoft browsers ignore it and use the hand value, while better behaved browsers take pointer and ignore hand.

Visual Hints

In a large form, it can be easy to lose track of the form field you’re currently filling in. A great trick for helping out is the following:

<style type="text/css">  
input {  
 border: 2px solid #ccc;  
}  
input:focus {  
 border: 2px solid #000;  
}  
</style>

This causes all input fields to have a 2 pixel wide gray border, while the input field on which the user is currently focused gets a black border to make it stand out from the others. There’s one caveat: IE on Windows doesn’t support the :focus pseudo-class! Thankfully, it’s possible to replicate the effect using JavaScript:

<input type="text" name="myfield" id="myfield"   
      onfocus="this.style.border='2px solid #000'"  
      onblur="this.style.border='2px solid #ccc'">

This brings the effect to IE, at the expense of a lot of extra typing. If you’ve got a lot of form fields on the page, it makes sense to do this instead, again making use of the addEvent function introduced above:

<script type="text/javascript">  
addEvent(window, 'load', function() {  
 var input, textarea;  
 var inputs = document.getElementsByTagName('input');  
 for (var i = 0; (input = inputs[i]); i++) {  
   addEvent(input, 'focus', oninputfocus);  
   addEvent(input, 'blur', oninputblur);  
 }  
 var textareas = document.getElementsByTagName('textarea');  
 for (var i = 0; (textarea = textareas[i]); i++) {  
   addEvent(textarea, 'focus', oninputfocus);  
   addEvent(textarea, 'blur', oninputblur);  
 }  
});  
function oninputfocus(e) {  
 /* Cookie-cutter code to find the source of the event */  
 if (typeof e == 'undefined') {  
   var e = window.event;  
 }  
 var source;  
 if (typeof e.target != 'undefined') {  
    source = e.target;  
 } else if (typeof e.srcElement != 'undefined') {  
    source = e.srcElement;  
 } else {  
   return;  
 }  
 /* End cookie-cutter code */  
 source.style.border='2px solid #000';  
}  
function oninputblur(e) {  
 /* Cookie-cutter code to find the source of the event */  
 if (typeof e == 'undefined') {  
   var e = window.event;  
 }  
 var source;  
 if (typeof e.target != 'undefined') {  
    source = e.target;  
 } else if (typeof e.srcElement != 'undefined') {  
    source = e.srcElement;  
 } else {  
   return;  
 }  
 /* End cookie-cutter code */  
 source.style.border='2px solid #ccc';  
}  
</script>

The cookie-cutter code in the above deals with some cross-browser compatibility annoyances, and is discussed in my previous article.

Enhancing Text Entry Fields

The most common form field is <input type="text">. We’ve already seen how auto-focusing on this when the page loads can make a nice enhancement. A useful trick for fields containing a default value that needs to be changed is the following:

<input type="text" name="myfield" id="myfield" size="30"   
      value="This should be changed"  
      onfocus="this.select()">

When the field receives the focus, the text inside it will be instantly selected; it will be over-written the moment the user starts to enter their own text. This is also useful if the user is likely to copy and paste the text from the widget, as it saves them from having to first select it.

Here’s a nice trick for forms that are being used to create something that has an obvious title — for example, an email, or an article on a Website:

<input type="text" name="title" id="title" size="30"   
      onkeyup="document.title = 'New item: ' + this.value">

This creates an effect similar to many popular email programs, where the text in the title bar of the document changes as the subject of the email is typed. This could be particularly useful in an environment where multiple windows are likely to be open at once — a Webmail client, for example.

On a related note, sometimes the value of one form field can by initially guessed by looking at the value of another. A classic example is a content management system where each entry has a human readable title and a unique URL. The URL can default to matching the title, but with punctuation removed and spaces converted to underscores. Here’s the code to do that:

<input type="text" name="title" id="title" size="30"   
      onkeydown="document.getElementById('url').value =    
               this.value.replace(/[^a-z0-9 ]/ig,  
               '').replace(/ /g, '_')">  
<input type="text" name="url" id="url" size="30">

The critical thing here is that the user can still over-ride the guessed value for the URL if they want to by entering text directly in the field. If you just want to create a URL from a title without any intervention from the user, it’s best to do so in the server side code that processes the form.

Validation

Client side form validation is one of the most popular uses of JavaScript. Before we go on, I’d like to point out that if you’re building a server side application you should always check that data is valid in your server side code, whether or not you have used client side validation. Not doing this can leave your application wide open to all manner of unpleasant security problems — remember, malicious attackers know how to disable JavaScript in their browser. This point cannot be stressed enough. We now return to our regular scheduled programming…

Validation is a big topic, and one that has been covered extensively in tutorials all over the Web. Rather than rehash old ideas, I’m going to focus on a more usable way of validating user input. For instant feedback to the user, how about displaying an icon next to each form field that indicates whether or not that field has been correctly completed? Such an icon can be hooked straight in to the label elements we added earlier, and changed by using JavaScript to alter the label element’s class attribute.

Here’s a simple example for a required form field, broken down in to the CSS, the JavaScript and the HTML:

<label for="subject" class="required">Subject:</label>   
<input type="text" id="subject" name="subject" size="40"    
      onblur="checkRequired('subject');">

This is simple enough. The label element starts off with a class of "required" to visually indicate that the field is a required field. The JavaScript function checkRequired('subject') is called onblur, which refers to the point at which the focus moves away from the field.

<style type="text/css">   
label {  
 padding-left: 22px; /* To leave room for the icon */  
}  
label.required {  
 background-image: url(required.gif);  
 background-repeat: no-repeat;  
 background-position: 3px 0px;  
}  
label.problem {  
 background-image: url(caution.gif);  
 background-repeat: no-repeat;  
 background-position: 3px 0px;  
}  
label.completed {  
 background-image: url(complete.gif);  
 background-repeat: no-repeat;  
 background-position: 3px 0px;  
}  
</style>

The CSS gives each label a left padding of 22 pixels. The icons we’ll use will each be 15×15, which gives us a little room to spare. Special classes of required, problem and completed are defined, each with their own background icon positioned to appear in the padding to the left of the form text.

<script type="text/javascript">   
function getLabelForId(id) {  
 var label, labels = document.getElementsByTagName('label');  
 for (var i = 0; (label = labels[i]); i++) {  
   if (label.htmlFor == id) {  
     return label;  
   }  
 }  
 return false;  
}  
function checkRequired(id) {  
 var formfield = document.getElementById(id);  
 var label = getLabelForId(id);  
 if (formfield.value.length == 0) {  
   label.className = 'problem';  
 } else {  
   label.className = 'completed';  
 }  
}  
</script>

Here, we define two JavaScript functions: one to find the label associated with a specific ID, and another, which checks that a specified form field has something in it, and sets the associated label’s class accordingly. This is the simplest possible case for validation; additional functions can be written to cope with problems such as checking that email addresses are in a useful format. This technique could be taken even further by disabling the submit button until all the form fields have been correctly completed; however, if this is done, it is vital that the initial disabling of the submit button take place in the JavaScript, to ensure that non-JavaScript enabled browsers can still use the form.

The last trick I will introduce revolves around data that has a very specific format. Rather than reject a user’s input if it doesn’t match the format rules perfectly, it is sometimes possible to reformat the user’s data once they have entered it. A classic example is a form field for accepting US phone numbers. US phone numbers, when the area code is included, are exactly 10 digits long. The traditional way of displaying them is (785) 555-5555. Using JavaScript, we can take the user’s input, strip out all non-digit characters and, provided we are left with 10 digits, reformat them to look like the above example:

<script type="text/javascript">   
function checkPhone() {  
 var phone = document.getElementById('phone');  
 var label = getLabelForId('phone');  
 var digits = phone.value.replace(/[^0-9]/ig, '');  
 if (!digits) {  
   return;  
 }  
 if (digits.length == 10) {  
   phone.value = '(' + digits.substring(0, 3) + ') ' +    
     digits.substring(3, 6) + '-' +    
     digits.substring(6, 10);  
 } else {  
   phone.value = digits;  
 }  
}  
</script>  
 
<label for="phone">Phone Number:</label>  
<input type="text" id="phone" name="phone" size="20"    
      onblur="handlePhone();">

This technique can be taken even further to allow multiple ways of entering structured data, such as a date, with any recognised values being converted to a standard format. My better date input script does exactly that, and I recommend you check out the source code to see exactly how it works.

To better illustrate the ideas in this article, I’ve put together this simple form that demonstrates some of the techniques introduced. I hope I’ve inspired you to think about new ways of improving your form’s usability using JavaScript and CSS.

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.

No Reader comments

Comments on this post are closed.