Forms.. <ul> and <label> or <table>?

I was just building a contact form on a page, and thought about how much you have to go through to stylize a series of UL and LABEL tags plus float and position the crap outta them just to get them the way you want, when it occurred to me that tables might be easier.

Plus, is using UL’s, LI’s and Label’s all over the place any more semantic than using tables?

Using a table just seems like less headache to me.

There should be a special set of tags for contact forms, it seems forms have an element structure of their own, and probably don’t fall in the category of “list items”.

Semantically a <ul><li> would make hte most sense while using forms (so would a dl/dt since they have some sort of relationship to each other)

Tables are generally easier to create columns but I doubt they are easier to make :).

Tables are menat for tabular data and nothing else. They aren’t meant to lay out forms. List items are more semantic :).

Forms very rarely consist of unordered lists, so using UL/LI is normally just as unsemantic as using TABLE.

LABEL for labels is definitely semantically correct, though.

Not to me. Tables just mean a lot of unnecessary bloated markup.

<form action="contact.php" method="post" accept-charset="utf-8">
  <fieldset>
    <legend>Contact Us</legend>

    <label for="name">Name</label>
    <input type="text" name="name" id="name">

    <br><label for="email">E-mail</label>
    <input type="text" name="email" id="email">

    <br><label for="msg">Message</label>
    <textarea rows="4" cols="80" name="msg" id="msg"></textarea>

    <br><input type="submit" value="Send">
  </fieldset>
</form>
fieldset {position:relative; padding-left:6em; padding-right:0.5em}
label {position:absolute; left:0.5em; width:5em}
input[type="text"], textarea {width:100&#37;; border:1px solid #000; margin-bottom:2px}

Not too hard, I think. Yes, you’ll need some hacks for buggy browsers like IE6 and Firefox, but that’s only a few more lines.

If you look around, you can find various forms without tables or lists.

Imaginkitty finally showed me where his multi-col tableless form is, lawlz:
http://imaginekitty.com/cssExamples/formHTML.html

Gary’s version is pretty much the same but smaller: http://gtwebdev.com/workshop/forms/form.php

Tyseen I think sent me this one, which is also well-done: http://www.gbjt.org.au/competitions/enrolment/

Recently I was making some forms in the design of another web site, where for the first time I ran into the IE margin-adding bug (where margins on forms, fieldsets, etc get added and added and added to certain inline/block elements like textareas), and so for the first time actually hacked for it… y wrapping a span around the textarea. Not really so bad.

Hard hacking for IE6 really only comes into play when you’re adding juicy bits like tooltip help text stuff, I’d say.

Do you want more examples? Or do you have a form you’re struggling with now? People are ready to help.

Sometimes a form really does belong in a table… because people are supposed to be filling out a table, like pricing. Otherwise, you wouldn’t want to semantically call a form something it’s not… screen readers are an example of a user agent that can tell what you used to build stuff, and it will tell people “this is a table” or “this is a list” in addition to “this is a form” (not like that, but you can navigate pages based on element type).

I made an example of a fairly [thread=619847]complex form[/thread] using semantic markup a while back. It does contain a couple of tables, but that’s because there is tabular information in it. Everything else is table-free, though.

Yes, there is a lot of CSS here, but it’s also a form that is rather more complex than most contact forms. :slight_smile:

Here’s something I did a while ago that might interest you – http://24ways.org/2006/showing-good-form – it’s a form laid out in a two-dimensional grid, implemented using only forms markup which degrades to a sensible semantic structure without CSS.

The article also explains how mixing non-forms markup into a form impacts negatively on screenreaders, and therefore why you shouldn’t do it.

That is an interesting article, and would not have been able to see that table as the kind of form you ended up with at the end (though looking at it, it certainly makes sense)… except so long as I don’t have the freedom to style it to look the way it must for all the other users in most or all user agents, I’ll probably still use a table when it’s a table. I haven’t run across a form that’s also a list but if it was I’d use a list.

I’ve used tables as forms when it made sense, and I tested it in JAWS 7 at the time I built it (not a substitute for all the readers I don’t have, I know).


        <form action="forms.html" method="post" id="formPrijzen">
	  <table class="prijzen" summary="Zet uw prijzen per week, midweek, weekeind, en nacht voor elk seizoen: Top, Hoog, Midden, en Laag, en dan ook Last Minutes">
            <caption>Zet uw Prijzen</caption>
            <thead>
              <tr>
                <th scope="col">Seizoen</th>
                <th abbr="per week" scope="col" axis="prijs">Prijs per week</th>
                <th abbr="per midweek" scope="col" axis="prijs">Prijs per midweek</th>
                <th abbr="per weekeind" scope="col" axis="prijs">Prijs per weekeind</th>
                <th abbr="per nacht" scope="col" axis="prijs">Prijs per nacht</th>
              </tr>
            </thead>
            <tbody>
              <tr class="top">
                <td scope="row" axis="seizoen">Top</td>
                <td>€ <input type="text" id="prijsTopWeek" name="prijsTopWeek" title="top seizoen week prijs"></td>
                <td>€ <input type="text" id="prijsTopMidweek" name="prijsTopMidweek" title="top seizoen midweek prijs"></td>
                <td>€ <input type="text" id="prijsTopWeekeind" name="prijsTopWeekeind" title="top seizoen weekeind prijs"></td>
                <td>€ <input type="text" id="prijsTopNacht" name="prijsTopNacht" title="top seizoen nacht prijs"></td>
              </tr>
              <tr class="hoog">
                <td scope="row" axis="seizoen">Hoog</td>
                <td>€ <input type="text" id="prijsHoogWeek" name="prijsHoogWeek" title="hoog seizoen week prijs"></td>
                <td>€ <input type="text" id="prijsHoogMidweek" name="prijsHoogMidweek" title="hoog seizoen midweek prijs"></td>
                <td>€ <input type="text" id="prijsHoogWeekeind" name="prijsHoogWeekeind"  title="hoog seizoen weekeind prijs"></td>
                <td>€ <input type="text" id="prijsHoogNacht" name="prijsHoogNacht"  title="hoog seizoen nacht prijs"></td>
              </tr>
              <tr class="midden">
                <td scope="row" axis="seizoen">Midden</td>
                <td>€ <input type="text" id="prijsMiddenWeek" name="prijsMiddenWeek" title="midden seizoen week prijs"></td>
                <td>€ <input type="text" id="prijsMiddenMidweek" name="prijsMiddenMidweek" title="midden seizoen midweek prijs"></td>
                <td>€ <input type="text" id="prijsMiddenWeekeind" name="prijsMiddenWeekeind" title="midden seizoen weekeind prijs"></td>
                <td>€ <input type="text" id="prijsMiddenNacht" name="prijsMiddenNacht" title="midden seizoen nacht prijs"></td>
              </tr>
              <tr class="laag">
                <td scope="row" axis="seizoen">Laag</td>
                <td>€ <input type="text" id="prijsLaagWeek" name="prijsLaagWeek" title="laag seizoen week prijs"></td>		  
                <td>€ <input type="text" id="prijsLaagMidweek" name="prijsLaagMidweek" title="laag seizoen midweek prijs"></td>
                <td>€ <input type="text" id="prijsLaagWeekeind" name="prijsLaagWeekeind" title="laag seizoen weekeind prijs"></td>
                <td>€ <input type="text" id="prijsLaagNacht" name="prijsLaagNacht" title="laag seizoen nacht prijs"></td>
              </tr>
              <tr class="lastminute">
                <td scope="row" axis="seizoen">Last Minute</td>
                <td>€ <input type="text" id="prijsLastminuteWeek" name="prijsLastminuteWeek" title="last minute seizoen week prijs"></td>
                <td>€ <input type="text" id="prijsLastminuteMidweek" name="prijsLastminuteMidweek" title="last minute seizoen midweek prijs"></td>
                <td>€ <input type="text" id="prijsLastminuteWeekeind" name="prijsLastminuteWeekeind" title="last minute seizoen weekeind prijs"></td>
                <td>€ <input type="text" id="prijsLastminuteNacht" name="prijsLastminuteNacht" title="last minute seizoen nacht prijs"></td>
              </tr>
            </tbody>
          </table>
	  <fieldset>
	  <legend>Opmerkingen</legend>
	    <label for="prijsOpmerkingen"><span>Overige opmerkingen met betrekking tot de prijzen:</span>
	      <textarea cols="60" rows="5" id="prijsOpmerkingen" name="prijsOpmerkingen"></textarea></label>
	    <input type="submit" class="submit" value="Stumbit!">
	  </fieldset>
        </form>


form {
  padding: 2px;
  background-color: #819825;
  border: 1px solid #536a20;
}

fieldset {
  border: 0;
}

legend {
  color: #000; /*IE*/
}

label {
  display: block;
  width: 100%; /*haslayout IE6, float wrapping*/
  overflow: hidden; /*haslayout IE7 and float wrapping Modern Browsers*/
}
	label span {
	  float: left;
	  width: 15em;
	  font-weight: bold;
	}

input {
  width: 4em;
}
	input.submit {
	  display: block;
	  width: 8em;
	  margin: 5px auto;
	}

table.prijzen {
  width: 90%;
  margin: 0 auto 20px;
  border-collapse: collapse;
  background-color: #fff;
}
	table.prijzen tr {
	  height: 2em;
	}

	table.prijzen th, table.prijzen td {
	  text-align: center;
	  vertical-align: middle;
	  color: #000;
	  border: 1px solid #000;
	}
		table.prijzen th {
	          width: 8.5em;
		}
		table.prijzen td {
		  white-space: nowrap;
		}
	table.prijzen td.lastminute, table.prijzen tr.lastminute {
	  background-color: #81bfff;
	}
	table.prijzen td.laag, table.prijzen tr.laag {
	  background-color: #9bda68;
	}
	table.prijzen td.midden, table.prijzen tr.midden {
	  background-color: #fffe7a;
	}
	table.prijzen td.hoog, table.prijzen tr.hoog {
	  background-color: #ffa405;
	}
	table.prijzen td.top, table.prijzen tr.top {
	  background-color: #ff8080;
	}

Not the best caption ever thought out, but here we were able to have a table, have it act like a table, be read like a table, while you can also simply go through it like a pure form. Partially this was also because the exact same table came back in the next step with the information the users had filled in.

*edit: Tommy, I had been looking for that earlier. Now I’ve copied it and reset the CSS into something I can read… I saw a lot of instances of
border: solid #000;
border-width: 0 0 1px;
any reason those were separated like that? Some browser bug?

Ideally I’d like to be able to link to that form in a version people can see (like the imaginekitty one and Gary’s) so I can add it to my links I spew out in forums… if you can’t host it, may I?

But did you test it in forms mode, or just normal reading mode?

Only forms mode, actually…
since upgrading to JAWS 10, I get automatically sent into forms mode. But I’m not sure if I’ve tested in that one. I had 7.1 for a long time, and that’s what I had back when I originally made the form.

I never tried to switch to table-anything… I’m mostly relying on the titles to do the work of labels (and that’s generally ok). But if you want to do a listen-through in older JAWS in just the read mode, you can read it as a table (I don’t remember if axis did anything back then, but I know version 10 understands it).

That’s interesting - I got completely different results when I tested mixed content forms mode, although that was using JAWS 6. I may have to rethink my initial premis.

Or maybe, just stop trying to hack things for screenreaders. I’m barely competent at their use anyway, and hacking for devices is a vicious circle as we know.

I still think it’s a bad idea to mix forms and non-forms markup, for semantics reasons, but perhaps my belief that it causes issues for screenreaders is wrong or irrelevant.

Because I always doubt myself, and because it’s been quite a long time since I tested my forms (they were tested in JAWS7 which meant IE6 only… I could SayAll in Mozilla but the other quickkeys went bonkers…), I went back to see what they did again, with the form I posted above.
I never had a copy of JAWS6 but it’s one I would consider buying if the anecdotal info I hear is true (that it’s still heavily used in Europe).

If you just go through the page in SayAll or whatever (which plenty of people, if they are impatient like me, may not do), when you get to the form table in JAWS7 , it’s announced as a table and the summary is read out (on the actual page where the form is I don’t think it’s a good idea to leave description or instructions in the summary… better to have it outside and before), and everything is listed/mentioned as table stuff, til you get to my first input. You realise it’s a input and JAWS7 you need to specifically go into Forms Mode yourself so I hit enter and from then on, it’s as if it’s just a form with the titles read out (by default) type-in-edit-text.
After the last input of the form, you’re still in forms mode and I have another form question in the form but outside the table… I’m told I’m leaving the table and the legend of the next fieldset is read out and everything finishes like a typical form.

None of the table-ness really appear… if you are in Forms Mode, then as usual only form controls are read out. I didn’t think of it but I could have made the left td’s labels, that might have been smarter.

JAWS10 (which I can also test in Mozilla and that’s pretty much my default browser with JAWS now) pretty much acts the same way except it wants to jump you into forms mode. No mention of anyone being a table anywhere is mentioned until you go from the last input in the table to the next non-table fieldset… but if I’m sayAlling into the page, while I am shoved into Forms mode the summary does get read first.

Or maybe, just stop trying to hack things for screenreaders. I’m barely competent at their use anyway, and hacking for devices is a vicious circle as we know.

I hack for them the way I hack for IE6: if I can keep my semantics and it’s not a huge weird workaround I’ll do it, but if the bug really causes problems for other users, I have to either think of something else, or consider dropping support there. I’m rather unhappy that I have zero input or feedback over whether any of my pages are visited by a screen reader (besides mine) and if so, which versions.

JAWS6 is so nastily buggy I really don’t like the idea of hacking for it… though it might be the most widely used on in my area. That would also be a reason to continue catering for IE6 since Mozilla worked buggy at best.

JAWS10 on the other hand is pretty nice and I can use it in other browsers.

I still think it’s a bad idea to mix forms and non-forms markup, for semantics reasons, but perhaps my belief that it causes issues for screenreaders is wrong or irrelevant.

No, god, you’re absolutely right… most forms have explanations and other important text in non form controls and you totally don’t hear them! Not unless you go through the form first in reading mode which, esp if your reader automatically starts you out in forms mode, why would you? I’d be too impatient.

But the thing about whatever you’re wrapping your form controls in is, at least in JAWS, if you make sure all the info that’s relevant is in the control (and so don’t rely on any table semantics or list semantics if using those), you can make it act like a regular form. What’s valuable about your page you linked to is that you can stuff your tabled form with all the correct table semantics you want but the reader user is not able to take advantage of them if they’re filling out the form… and so information is lost, and people might not realise that.

If I were to rewrite my table and make it more “form-y” I’d make the row-scoped td’s labels and treat them similar to how I do multi-input labels like license plates and birthdates… currenty I hide labels and try to let the legend start things off. Orca doesn’t seem to read my titles but I am quite sure I’m doing it wrong : )

I’ve been trying to test this stuff in Orca but Orca works just so totally differently… no virtual buffer and it seems not to have a forms mode (or I’m just not finding it). Sometimes I wonder if we waste our time checking in some screen reader when the other five in use work completely differently. : (

Yes, I think we do - I’ve all but stopped doing so. Given what a vicious circle device hacking is (we hack for the device, the device changes to negate the hack, we find a new hack, etc.) and given that the screenreader vendors almost exclusively refuse to participate in a dialog with developers, I really think it’s best just to leave it alone. Focus on clean semantic content, and leave the vendors to worry about how to interpret it for their users.

I am still glad you posted the link, though, because while I ended up agreeing with the commentors more (I want to follow my instincts re semantics when I can), it is something to at least keep in the back of our minds… and while I like to feel better when someone like Gez Lemon says “titles are safe substitutes for labels in forms” [u]because they work in JAWS and W-E[/i], I’ll then wonder about Orca or NVDA. Or HAL. Or VoiceOver (what do I do? Shell out boku bucks for a Mac? I don’t test in “real” Safari for that very reason!).

BTW while the Big Guys may not be developer friendly, I think when Orca’s ready (I don’t think it is, yet) web devs and Mozilla guys (since they seem to be building for Firefox as if that’s the only worthy browser lawlz) should get together, cause I think the open-source projects will be willing to work with web devs. I’ve seen the same arguments that web devs have (should web sites be built more accessibly even though most sites are built by robots/templates/people who don’t know/care or should we make AT work better?) over in places like orca mailing lists. Same issues.