Showing Good Form

Earlier this year, I forget exactly when (it’s been a good year), I was building a client site that needed widgets which look like this (designed, incidentally, by my erstwhile writing partner, Cameron Adams):

Building this was a challenge not just in CSS, but in choosing the proper markup – how should such a widget be constructed?

Mmm … markup

It seemed to me there were two key issues to deal with:

The function of the interface is to input information, so semantically this is a form, therefore we have to find a way of building it using form elements: fieldset, legend, label and input

We can’t use a table for layout, even though that would clearly be the easiest solution!

Abusing tables for layout is never good – physical layout is not what table semantics mean. But even if this data can be described as a table, we shouldn’t mix forms markup with non-forms markup, because of the behavioral impact this can have on a screen reader:

To take a prominent example, the screen reader JAWS has a mode specifically for interacting with forms (cunningly known as “forms mode”). When running in this mode its output only includes relevant elements – legends, labels and form controls themselves. Any other kind of markup – like text in a previous table cell, a paragraph or list in between – is simply ignored. The user in this situation would have to switch continually in and out of forms mode to hear all the content. (For more about this issue and some test examples, there’s a thread at accessify forum which wanders in that direction.)

One further issue for screen reader users is implied by the design: the input fields are associated together in rows and columns, and a sighted user can visually scan across and down to make those associations; but a blind user can’t do that. For such a user the row and column header data will need to be there at every axis; in other words, the layout should be more like this:

And constructed with appropriate semantic markup to convey those relationships. By this point the selection of elements seems pretty clear: each row is a fieldset, the row header is a legend, and each column header is a label, associated with an input.

Here’s what that form looks like with no CSS:

And here’s some markup for the first row (with most of the attributes removed just to keep this example succinct):

The span inside each legend is because legend elements are highly resistant to styling! Indeed they’re one of the most stubborn elements in the browsers’ vocabulary. Oh man … how I wrestled with the buggers … until this obvious alternative occurred to me! So the legend element itself is just a container, while all the styling is on the inner span.

Oh yeah, there was some CSS too

I’m not gonna dwell too much on the CSS it took to make this work – this is a short article, and it’s all there in the demo [demo page, style sheet]

But I do want to touch on the most interesting bit – where we get from a layout with headers on every row, to one where only the top row has headers – or at least, so it appears to graphical browsers. For screen readers, as we noted, we need those headers on every row, so we should employ some cunning CSS to partly negate their visual presence, without removing them from the output.

The rendered width of the element is preserved, ensuring that the surrounding label is still the same width as the one in the header row above, and hence a unified column width is preserved all the way down. But the element effectively has no height, and so it’s effectively invisible. The styling is done this way, rather than just setting the height to zero and using overflow:hidden, because to do that would expose an unrelated quirk with another popular screen reader! (It would hide the output from Window Eyes, as shown in this test example at access matters.)

The finished widget

It’s an intricate beast allright! But after all that we do indeed get the widget we want:

It’s not perfect, most notably because the legends have to have a fixed width; this can be in em to allow for text scaling, but it still doesn’t allow the content to break into multiple lines. It also doesn’t look quite right in Safari; and some CSS hacking was needed to make it look right in IE6 and IE7.

Still it worked well enough for the purpose, and satisfied the client completely. And most of all it re-assured me in my faith – that there’s never any need to abuse tables for layout. (Unless of course you think this content is a table anyway, but that’s another story!)

About the author

James Edwards (aka brothercake) is a freelance web developer based in the United Kingdom, specialising in advanced JavaScript programming and accessible website development. He is an outspoken advocate of standards-based development, an active member of WaSP (The Web Standards Project), and creator of the Ultimate Drop Down Menu system – the first commercial DHTML menu to be WCAG compliant. James was also co-author of The JavaScript Anthology, published by SitePoint in 2006.

Brought to you by

Related articles

Ruth John breaks out of the browser and projects a Christmas sound and light show with some JavaScript, the Web MIDI API and a portable A/V pack. Don’t make a spectacle of yourself at the party this year – take it outside!

Jack Franklin introduces ECMAScript 6’s module system with some tools to help us start using this powerful new JavaScript functionality of tomorrow right now. Always good to be ahead of the game – sorted out your Christmas shopping yet?

Jack Franklin darns the holes left in our applications by exploring how our client-side JavaScript frameworks might also be run on the server to provide universal support for all types of user. How will you react when you see mommy kissing Server Claus?

Remy Sharp picks that old chestnut – tabs – and roasts it afresh on the open fire of JavaScript to see how a fully navigable, accessible and clickable set of tabs can work. Everybody knows some scripting and some CSS can help to make your website bright. Although it’s been said many times, many ways, please be careful to do it right.

Chris Coyier grabs Grunt by the snow-white fur of its Santa suit and places it firmly (but gently) in your webdev grotto to dish out its Christmas gifts — and maybe even chuck you under the chin and sit you on its broad and comfy knee. Not at all creepy. No. Nope.

Tom Ashworth exhorts us to become more familiar with JavaScript so we can better understand and use new tools like Node and Grunt — it’s always the box the gift comes in that’s more useful and fun, right?