Article
Simple Tricks for More Usable Forms
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 15x15, 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.