Introduction
The most monotonous entities in the known universe, forms, are a staple of every web programmer’s balanced diet. Whether we like them or not, forms are the gatekeepers to our site’s goodies and often their design alone determines whether a user will try what you’re selling or simply walk away. Without pomp or circumstance, here are ten tips to transform your plain vanilla into double chocolate chunk with marshmallows.
The Code
The code examples below will not work “as is.” They are dependant on an external library, prototype.js with addEvent included. Additionally, the functions below need to be attached to events, such as onclick
or onmouseover
. Check back for a downloadable example file.
1. Remember Your Markup
We’ve notice a lot of people forgetting to use the tools that are already made accessible to them by the very medium that they work in. And so we’ve highlighted a few HTML elements below that are made especially for forms. Just to refreshen the ol’ web noggin.
Label
A label is used to attach information to a control. If you focus on a label, its associated control will gain focus. This is useful when a user clicks on a label name and the associated field gains focus.
<label for="email">Email: </label>
<input type="text" id="email">
or
<label>Email: <input type="text" id="email"></label>
Fieldset
“The FIELDSET element allows authors to group thematically related controls and labels. Grouping controls makes it easier for users to understand their purpose while simultaneously facilitating tabbing navigation for visual user agents and speech navigation for speech-oriented user agents. The proper use of this element makes documents more accessible.”
Legend
“The LEGEND element allows authors to assign a caption to a FIELDSET. The legend improves accessibility when the FIELDSET is rendered non-visually.”
Tabindex
“This attribute specifies the position of the current element in the tabbing order for the current document. This value must be a number between 0 and 32767. User agents should ignore leading zeros.The tabbing order defines the order in which elements will receive focus when navigated by the user via the keyboard. The tabbing order may include elements nested within other elements.”
Accesskey
“This attribute assigns an access key to an element. An access key is a single character from the document character set. Note. Authors should consider the input method of the expected reader when specifying an accesskey.”
Password
By adding type=”password” to your input field, characters entered will be transformed into a series of asterisks.
“Application designers should note that this mechanism affords only light security protection. Although the password is masked by user agents from casual observers, it is transmitted to the server in clear text, and may be read by anyone with low-level access to the network.”
2. CSS
This isn’t new, but CSS can turn your eye sore of a form into something negative fugly. There is no need to reinvent the wheel here, so check out the following sources on enhancing your form with some CSS and a little Javascript.
Style Those Buttons - The Man In Blue shows us how to make those buttons not look so cheap.
Niceforms - Niceforms does a great job of turning that ugly form into something much more tolerable using a little CSS action.
Hide Optional Fields - In this example, a little CSS and Javascript is used to make a form better looking and more usable.
CSS Forms - Jeff Howdens shows us how to create a well layed out and styled form without using tables.
3. AutoTab
When navigating through a form, the user traditionally presses the tab button in order to advance to the next form control. This AutoTab function automatically sets the focus to the next control after the control’s maxlength is reached. This allows for the user to no longer manually tab through fields with a maxlength. This function is particularly useful for fields such as social security or phone numbers containing a character limit for each input field. For example, after a user enters the area code of a phone number, the form automatically tabs to the next input box allowing the user to continue entering their phone number without interruption.
To flag an input element to be autotabbed, you only need to include three things in your markup: tabindex, className of autoTab
and maxlength.
<input type="text" name="areacode" class="autoTab" tabindex="1" maxlength="3" />
On page load, it’ll attach the events to input fields for autotabbing. If a field has a maxlength and that maximum is reached, the focus is automatically set to the control with the next highest tabindex value. Here’s a quick look at our function, autoTab()
:
function autoTab(e) {
if(this.value.length == this.getAttribute("maxlength") &&
e.KeyCode != 8 && e.keyCode != 16 && e.keyCode != 9) {
new Field.activate(findNextElement(this.getAttribute("tabindex")));
}
}function findNextElement(index) {
elements = new Form.getElements('shippingInfo');
for(i = 0; i < elements.length; i++) {
element = elements[i];
if(parseInt(element.getAttribute("tabindex")) == (parseInt(index) + 1)) {
return element;
}
}
return elements[0];
}
Two things worth noting:
You could also use
input.form[(getIndex(input)+1)].focus()
, but that causes a weird javascript error when using Firefox. An example of this can be seen at The Javascript Source.When a user presses shift-tab, the previous element should still get focus, and autotab with automatically disable.
4. Field Information
It’s always good policy to provide information describing a field’s requirements and restrictions. How else is the user going to know a password must have 3 capital letters, an exclamation point and be somewhere between 6 and 17 characters long? Inspired by the forms used over at Tangent, we came up with some additional suggestions.
Store all related information in a fields label tag. You can place a className of required, an accesskey, and a descriptive title in there, so that all information is in one place. This makes it easier to roganize, and easier for JavaScript to pull from.
We choose to use
onfocus
instead ofonmouseover
when displaying information to the user. While mostly personal preference, it is still nice to know that the proper information will be displayed on the field with focus rather than where the mouse is.It is easier to give labels an id similar to the field they related to. For example, if a field is named
fname
, call the labellfname
. It makes things much easier on the JavaScript side to pull information. You can see the labels title being accessed below:p = document.createElement("p");
p.innerHTML = $("l" + this.id).title;
span.appendChild(p);
5. Error Displays
When a user makes a mistake, it’s your duty to show them errors quickly and efficiently. Here are some ideas to make your forms display errors better:
Don’t just show the user one error. If they left 3 required fields blank, make sure that you tell them they have three errors, this way they can correct them all in one fell swoop.
Provide as much information to the user beforehand as possible. Examples of this would be marking a field as required, or explaning the minimum password length (See #2 above).
Be aware of the three validation options at your disposal: 1) you can give responsive feedback straight from the JavaScript. The user benefits from instant feedback, but you will have to duplicate your validation functions on the client and server. 2) You can provide Degradable Ajax Validation that gets rid of the duplicated code, but increases the server load. 3) You may validate only on form submit which leaves you with no duplicated code, no additional server load, and unfortunately, no instant feedback.
Put some effort into the display of your error messages. Make them bold, noticable, and throw in a bit of creativity. It is also best to stick with colors that the user is comfortable with:red for errors, yellow for warnings, green for success. Obviously you can switch those up based on your evaluation, but going to far and making an error message pink could cause some confusion.
6. Postbacks
There is nothing worse than filling out a form, encountering an error, and having to retype all of your information all over again. In order to save your users from needless frustration, we need to ensure that all data is preserved. This means if there is an error, the fields should be repopulated. If we have a multistep form, back and forward navigation should also keep the form populated. A common approach is to set a form’s action to it’s current URL. That way, you can read in the form value and populate the fields immediately if there is an error. For example, just set the value to the post:
<input type="text" name="fname" value="<?=$_POST["fname"] ?>" />
And the field will be populated. If there is no error, just redirect the page to the form completion page.
7. onFocus
Visual cues, such as changing a field’s border color, help show the user which field has focus. CSS provides an easy solution for adding borders with the border selector, but this feature isn’t currently supported in IE and doesn’t work at all with select elements. Our solution creates custom borders and backgrouds by adding a span to each form element using a little J-Juice.
The concept here is that by enclosing our form element within a span, we can produce a unique effect. Don’t worry, you don’t need to hand code the span — this unobtrusive JavaScript function will dynamically add and remove it automatically. The nice part is that the span can have background images, borders and any other desired combination of the two to create an effect that will work on text, textarea, and select elements. Here is how everything looks when it is done:
<span class="focus">
<input type="text" id="fname" name="fname" />
</span>function showFocus() {
this.parentNode.className = "focusHover";function hideFocus() {
this.parentNode.className = "focus";
}
The reason a state is needed for the span when the field does not have focus is to prevent shifting of the page. For example, if our custom span has 3 pixels of padding onfocus
, we need 3 pixels of transparent padding when there is no focus, so that we do not see form elements “jumping” as the user navigates them.
8. Label Click
When a label receives focus, whether it be through onclick or through accessKeys, the associated element specified in the labels for
attribute should receive focus also.
When a LABEL element receives focus, it passes the focus on to its associated control.
Unfortunately, this is not guaranteed in all browsers. To remedy the situation, a simple JavaScript function will do the trick:
function initLabels() {
labels = document.getElementsByTagName("label");
for(i = 0; i < labels.length; i++) {
addEvent(labels[i], "click", labelFocus);
}
}function labelFocus() {
new Field.focus(this.getAttribute('for'));
}
9. Double Submit
Nooo! Our user has submitted the form twice, probably because the site did not respond fast enough. Not only will the data be processed twice, but the last submission will be the active submission which often will provide errors that will confuse the user even more. Three things to keep in mind for this situation:
If JavaScript is enabled, use it to submit the form. After one submission, disable the button.
If JavaScript is not enabled, provide your users with a clear message asking them not to submit critical data more than once.
Do what you can on the server to prevent the processing duplicate information. Track payments, accounts, etc and flag them when an action has occured. This way, the second round of processing will just be ignored.
10. Leftovers
And we’re going to close this off by highlighting some awesome links to some features people have already implemented, or could implement. You may not need them in your particular situation, but they’re definitely lifesavers when you do.
Mini Calendar - Whenever there is a date field, it is always best to provide a popup calendar. Ideally, this calendar will not open in a new window, and will be responsive. To get started, Dynarch has the best solution.
Combo boxes - The element that missed the HTML cut is the half select, half text input breed known as the combo box. This concept allows the user to type in their own option if they can’t find what they’re looking for in the drop down. Take a look at Upgrade Your Select Element to a Combo Box to see how we approached a solution.
Visual Maps - Just like the popup calendar, popup maps can also be effective. Take a look at Orbitz, and click on airport code. That takes you to a text listing of all airports. This could easily be a dynamic in page popup that displays a clickable map, which in turn popualtes the field when clicked.
These are some ideas to get you started. Please let us know if you have more to add to the list.
I think I’m right in saying that, even if you implicitly associate a LABEL with its form field, you still need to explicitly associate it using the FOR attribute for everyone’s favourite browser…
Yes, Matthew, you’re right.
Good article, really useful!
Re: #6, the value of the request variable should be passed through htmlspecialchars() [or equivalent for languages other than PHP.] Otherwise, values containing quote characters will result in mangled HTML.
Everyone needs a hug.
I don’t recognize some of those method calls, like Form.getElements(), Field.focus() and Field.activate(). Is a custom library being used (almost looks like Prototype), or am I just dense?
Thanks for the informative article!
Everyone needs a hug.
Sorry about that (previous misfire)!
What I was trying to say was I’m not so sure about the AutoTab feature. From a usability point of view, it might be unexpected for the focus to jump when the field value hits maxlength.
Great article though Chris and good pooling of resources! I’ll definitely be coming back to this one!
I’d question the Auto-tab tip, since this is not implemented very much and most people are so used to tabbing through fields (or clicking for those that don’t know better). I was just at a site that made you enter your birthdate (absolut.com) to enter. I entered the year, pressed tab, not realizing that it had auto-tabbed itself already to the first digit month field, so I was taken to the second digit part of the month field, and was already entering in “19” when I realized, but since I entered in info in the second month field it had auto-tabbed me to the day field. So, I would up with 1974 | _ 0 | 41 for the YYYY | MM | DD fields. (EAch was separate, so there were a total of 8 fields. See the site to see what I mean.)
I had to shift-tab/click back and correc the info. In the end, the auto-tab feature made filling out this form take at least twice as long and twice as hard as it should have.
I think some objective user testing is needed here. Unless everyone starts implementing auto-tab and users start to be able to expect it/assume it to be there for them, I think leaving the user to press tab is the best way to go at this point.
I wrote a tid-bit just a while back on ‘focusing the user’. http://www.dustindiaz.com/focus-the-user/
Seems like it accomplishes a similar goal of directing the user. No matter where the user tabs or clicks to in the form, the fieldset ‘lights up’ - and even within the fieldset, the element that is focused lights up.
For Autotab, I agree it is not best used on a common web page that anyone can visit. However, on internal forms that are used by the same people on a daily basis, it is invaluable. At least, when I have implemented it in those situations people have loved me for it.
Maybe I’m missing something, but a lot of the script in these examples won’t work as-is. To echo Daniel’s concerns, it looks like you’re using a custom JS library to help things along, but forgot to mention it in the article or include it in the code samples.
There’s no native browser support for a “Field” object. Nor does declaring “autoTab” as a classname automatically attach an autoTab() JS function to a field. That’s usually done with event handlers such as onclick or onchange. If additional code was used to attach these functions to their proper handlers, it was left out of the example.
Under “Label Click” there’s a reference to a JS function called addEvent() which doesn’t exist in native code. I should know, because I wrote it ;)
The “onFocus” example doesn’t work at all, since there’s nothing invoking the showFocus() and hideFocus() functions. Was there additional code left out?
It might be a good idea to revise the sample code with references to whatever libraries were used, if any. Otherwise, people are likely to cut-and-paste these examples into their own apps and become confused when they see “Field is undefined” errors and the like.
Scott,
Im guilty for forcing prototype.js on everyone. I’ll go ahead now and edit the feature to show where the additional code is coming from.
For attaching of events, all of the code was left out. It was assumed that all of these functions would be called after an event was attached to them. This was done to keep the article at a reasonable length. Chris will be out most of the day, so I’ll make a downloadable file to show how all of the events get attached.
Nice article! Some reservations though:
Be very careful when using the accesskey and tabindex attributes. The source order of the form controls should make sense, thus making tabindex irrelevant, and using accesskey is problematic since there is no easy way for the user to know about the shortcut keys and they may interfere with browser or operating system shortcuts. One more vote for “be careful with AutoTab”. I’m also somewhat skeptical to using CSS and JavaScript trickery to change the look of form controls too much. Besides, it does not work very well cross-browser: Styling even more form controls.
Apologies if my previous comment comes off as, uhm, terse. It wasn’t intentional.
I think I’ll go take a nap.
a few minor nitpicks:
tabindex can cause some problems in certain (admittedly older) browsers; i seem to recall particularly older builds of mozilla which, as soon as there was a single tabindex, removing anything without a tabindex from the tabbing order.
as far as i know, current screen readers will not see any javascript generated content; also, innerHTML is not part of the DOM arsenal - as it seems that you’re only dealing with text, you could instead use createTextNode and append that as a child to the newly created paragraph.
the problem with the first suggestion arises when a user submits, the submit button is disabled, and then there is some problem like a server timeout; all a user can then do is refresh (which in some situations clears the form) - rare, admittedly, but it’s something worth keeping in mind.
No worries, Scott. Discussions wouldn’t be very much fun if everybody just agreed.
Patrick, good point about the tabindex. Also, although it’s not part of the official DOM, we are still choosing to use innerHTML. Some of the reasons why can be found at http://www.quirksmode.org/dom/innerhtml.html . To each his own =p.
Re: AutoTab - I’m not a fan of this type of function. It breaks the consistency of behaviour a lot of users rely on and may lead to confusion. Its dependence on hidden information (maxlength) also means the user doesn’t know which fields will autotab and which won’t. Better to let the user decide where the focus goes IMHO.
Otherwise an excellent summary, thanks.
Perhaps the auto-tab could disable tabbing in the next input, before anything is typed in? i.e. have something like:
function autoTab(e) { if(this.value.length == this.getAttribute(“maxlength”) && e.KeyCode != 8 && e.keyCode != 16 && e.keyCode != 9) { newel = findNextElement(this.getAttribute(“tabindex”)) new Field.activate(newel ); newel.onkeypress = function (e) { // Or, you know, have your favourite version of addEvent var savedtab = this.tabIndex if(this.value.length == 0 && e.KeyCode == 9) new Field.activate(findNextElement(index-1)) // This is ugly, but i didn’t want to rewrite the damned thing } } }
Or something along those lines. I dunno. I hope you get the drift though.
Whoa, sorry to break the layout - didn’t realise your pre was so large.
I just wanted to chime in on the auto-tab debate.
My bank uses atuo-tabs for some of their online forms, and it makes me crazy.
Consider the scenario where the the user makes a mistake entering the last character of a phone number ofr example. How hard is it for them to change the data now?
For most of us, pressing tab or enter is an instinct. It requires no energy or thought to perform, and it is intregral to the way enter data. Pressing ‘tab’ or ‘enter’ signals that we are pleased with our choice. We need that cognitive opportunity to reevaluate what we have entered.
Changing this convention for fields that are fixed length forces us to think about a task which has been, and should be transparent.
We use extensive AJAX and javascript on our moving site, please check it out at moversbay.com
Please…
” />
At least add htmlentities() around the value, it’s the minimum.
Otherwise, nice article !
I’m not the first one here to say it, but autotab is Pure Evil most of the time. (I hate it when entering a phone number becomes a matter of ‘123 Tab 45 damnit backspace backspace shiftTab 456 Tab 78 damnit backspace backspace shiftTab 7890.’)
However, what I’m here to say is, if you are going to use autotab, please follow this article’s advice and allow shift-Tabbing and editing. There are few things in life more frustrating than clicking on, or shift-tabbing to, a field with an error only to have the cursor helpfully jump away from it. In the worst case (forms that won’t let you move back or clear the data), I’ve been known to start a processor-intensive background task, so I could slow the browser’s JavaScript engine down enough that I could delete a character before it had a chance to jump to the next field.
Leszek Swirski’s idea, a few comments up (disable Tab if autotab was just invoked and nothing has been typed in the following field), is brilliant, although it could be badly applied, especially if optional fields were involved.
Everyone needs a hug.
Label tag didn’t work with SAFARI 1.3.1. (OS X 10.3.9) Did you know a tip about this ?
@frederic You need to turn full keyboard access to enable tabbing to all form controls in Safari (and the OS): System Preferences > keyboard & mouse > Turn on full keyboard access
Just wanted to say one thing.
“… negative fugly …”
Very nice read. Makes wanna change my forms here and there. Thanks.
Just wanted to echo Joshua’s comment: Including form input back in the source like that is a huge XSS hole.
Even just doing this is a risk: “>
A victim can get sent to
http://myfavouritebank.com/login.php/" onSubmit="alert('Not so nice');
May not seem like much, but it’s a snap to insert in a handler that inserts an image or whatever to ship their login credentials off to some other domain.
Apart from that little gripe, a nice article, thanks!
One thing needs to be stated about the Postbacks:
Doing it this way throw an error of level E_NOTICE when you first go to the page.
A better solution is this:
” name=”email” id=”email” />
By default, Notices don’t show up, but programmers (should) develop with error_reporting set to E_ALL, which will fill all your fields with “Notice: undefined index email….”
Just a heads up :)
Um.. stripped out my point, LOL…
Anyways, her is what I originally wrote:
” minues the spaces, of course :)
In addition to “1. Remember Your Markup”:
the optgroup tag is one of the most excellent ones I re-discovered lately. It allows you to group various option elements (which reside in a select element) into 1 group (with a title attribute (caption)).
Yeah, you might want to try this to remove the XSS security issue:
” />
AutoTab defined in third paragraph here is not OK. You put JavaScript function name into CSS class definition (!?) What!?
On page load a loop goes through all elements with a className of autoTab and attaches an event ot them that calls the JavScript function autoTab().
That’s exactly what I am looking for, the loop that loops through all input fields with className autoTab and attaches events dynamically but there’s no such a loop!
AutoTab functionality (when input field maxlength reached, go to next tabindexed form field).
Is there a demo page that can show your specific autotab script function in action? Or, show the rest of the componets that would make the script work?
I would also like to see a demo. Here’s what I’ve come up with, but it’s causing an error in IE:
[code]
[/code]
You’re going to want to include this: [script type=”text/javascript” src=”scripts/prototype.js”][/script] obviously replace the square brackets with angle brackets.
and enclose the script above in one of these fellas: [script type=”text/javascript”] [/script]
Sorry about that.
So if anyone can tell me why IE doesnt like the this.value.length I would really appreciate it.
Thanks!
great tips…
Great article, but as so often before - why cant we download an example of the code in action. You made a great article - now go the last 1% and add the full code in an example.
buy tramadol online cod
http://voidadmin.peep.coma.ua/buy-tramadol.html
AutoTab is awful. It hurts usability in the name of saving a single keystroke.
Don’t just show the user one error. If they left 3 required fields blank, make sure that you tell them they have three errors, this way they can correct them all in one fell swoop. I don’t agree that this is a one sided debate for JS validation. Showing the user 3 mistakes may make it easier, but showing them 15 is just going to leave them lost. I prefer to show them one mistake at a time. They click okay and then they automatically get their focus moved to the correct field.
I want to give this article a hug.
Hi! Very nice site! Thanks you very much! v4xmEtIOW8
Just a couple of points I feel need responding to. I know this article is now nearly 1.5 years old, but I think that misgivings still need to be addressed.
First, in “Remember Your Markup”, your label examples don’t include a “name” attribute. While I understand that it was probably omitted for brevity, but for those users that are new at this, it’s important to know that fields without a name can’t be considered successful form fields, per the spec, and therefore won’t have their data included in the data submitted to the server.
Second, on tabindexes, I’d highly recommend against using them except in those cases where source-order tabbing isn’t the desired behavior. Using tabindexes in any other case only creates maintenance problems, situations where search/login/etc. forms that are part of a common design end up either having competing tabindexes or the user can’t actually get to other elements in the design (links, forms in the design, etc.) until after tabbing through every tabindex’ed form element on the page.
Third, for many reasons which have been researched, blogged, etc. to death over the past year, do not use accesskeys. If you don’t believe me, google it a little bit and you’ll learn what I’m talking about.
Fourth, like many others have already said, I must echo that autotabs are pure evil, with the exception being in a web-app environment with a closed group of users that can be adequately user-tested prior to the “live” roll-out.
Fifth, regarding error displays, never, ever rely solely on color to indicate an error as a greater percentage of people than you might suspect are color blind.
Sixth, I’ve been doing this a long time and can’t think of a single browser that “Unfortunately, this (label click) is not guaranteed in all browsers.”. Care to elaborate?
Seventh, when it comes to double-submits, the only time it’s permissible to disable the submit button after the first click is if the button is only disabled for a short period of time (approximately 5-10 seconds) and you let the user know when the form is submitted.
Eight, except maybe in a web-app with a controlled user-base, combo boxes are a bad idea.
Ninth, thanks for linking to my writeup about using CSS to layout/style forms.
this is statement i using
subMenu.innerHTML = “Recur every
i need here to use onfoucs here, how can is do it.
dsfsdfsd sfgsf efgsf
hi..good site..by..
ocymh
I’ve used Dynarch’s calendar for a while but now I’m getting a weird bug. When I’ve used the calendar to select a date if I tab on to the next field the date changes from something like ‘2006-10-01’ to ‘undefined’. Don’t suppose anyone has had a similar problem?
Very useful check list. However, may I just point out that when using postbacks it is highly advisable to sanitise the user input before placing it back into the form. Failure to validate user input during postback use could easily reulst in the injection of harmful code. :)
Fantastic website… Good resources for learning, easy to follow… Keep up the good work!!! Make your opinion about my resources :)
I’d love to see an update of this article.