Friday, June 09, 2006

Setting Focus Onload() - Helpful Ain't Always Usable

Usability has become more and more of a concern to me over the last couple of years, and I just had to vent about a very common feature on web forms that appears to be "helpful", but often isn't - setting focus to the first form field onload()

I've been asked to add this feature on forms many times, and on very simple, quick-to-load forms like a login form, then fair enough, it saves someone a click or a press of the tab key, and saving someone a click has to be A Good Thing™, right? It means they can start typing straight away, right?

Wrong. For more complex forms - for instance, if you have a WYSIWYG component in the form which takes a while to initialise - setting focus to the first element onload() can actually make the form LESS usable, not more.

Here's why:

If you set an onload event on the document, then it doesn't fire until all of the referenced elements within the document have finished loading. When you have a lot of elements - particularly common with WYSIWYGs - then it's quite possible for the referenced elements to take several seconds to finish loading after the form has already appeared.

So the sequence of events goes like this -

  1. Form appears

  2. User starts typing in the first field

  3. User completes this field, moves onto the second and starts typing

  4. ...repeat step 3 an arbitrary number of times, until...

  5. referenced elements like scripts, hit trackers, banner ads, captchas, WYSIWYG components finally all finish loading

  6. THEN the onload() event fires

  7. focus "helpfully" gets set to the first form field, usually while the user is in the middle of typing in a large textarea and - crucially - looking at their keyboard, not the screen

  8. user finishes what they're typing and looks up

  9. user realises that for the last 30 seconds or so, they've been typing into the first field, not the big textarea that they thought they were typing in.

    1. optional Brucie Bonus - As the first field on a form is nearly always fairly short, the maxlength has been hit quite early on, but the user didn't realise this because they were looking at the keyboard. Hence, user realises that the last X words they typed have just disappeared.

  10. user swears loudly and curses this damn web system that was supposed to solve all their problems but has just given them a load of new ones.

I know, I know, it's a simple thing, but it drives me completely incandescent with frustration when I realise that I've lost the big long chunk of text that I was typing because the focus has shifted.

It's almost as bad as when someone starts an IM chat with you and the window pops up and starts accepting input without you noticing, and then you suddenly realise you've accidentally sent your Mum a foul-mouthed tirade that was intended for something entirely different...


Martin said...

Here's a solution: instead of using onload, use setinterval to fire some "init" function every 200ms or something. In the function, check whether the form input exists (You can do this by calling getElementById, it returns a boolean false equivalent if the element doesn't exist). If it does, set the focus. With this method, you ensure that focus is set as soon as the input field is rendered.

I'm thinking of doing all my js initialising stuff this way from now on. Some JS frameworks do this already (I think the yahoo library does).

Martin said...

I forgot the last bit: use the onload event to stop the interval thing with clearInterval()

Phil said...

You answered your own question. Don't use this technique on complex forms. I've been bitten by the onload moving my focus too and I hate it. Glad you're blogging this to heighten the awareness of developers unconcerned for the user experience.

Alistair Davidson said...

Martin: I've thought about that idea before, but it just didn't quite feel right. Feels like a bit of kludge to me, and I don't like things that feel icky.

Another technique that I've tried is this:

When you're rendering the form on the server, you know what the default value is, because that gets written to the value="#myValue#" attribute.

( Also, setting the value of a form field to explanatory text is not required yet but is a proposed enhancement to the W3C accessibility guidelines )

So, in your onload handler, you can check that the value of the form field hasn't changed before setting focus.

Alternatively, add a keydown listener to the FORM element which sets a flag. The setfocus call should only run if this flag has NOT been set.