32

I want to display an HTML form containing labelled text fields, like this:

      First Name:  [_____________]
       Last Name:  [_____________]
   Date of Birth:  [________]

My obvious approach is to use a <TABLE> and simply place the labels and text fields in its cells, but is there a better way, e.g. a CSS-based approach?

EDIT:

  1. I'm looking for a way that reduces the verbosity in the HTML file.
  2. And yes, I'm looking for auto-sizing of the labels. See a related question about wrapping labels
Community
  • 1
  • 1
Tony the Pony
  • 40,327
  • 71
  • 187
  • 281

9 Answers9

36

If you need the labels to the left of the fields like that, just go ahead and use a table. Not only do tables degrade nicely on older browsers, but they auto-size the column of labels to the text in them (assuming you use white-space: no-wrap on the cells containing the labels, and/or — and this is true heresy — the trusty old nowrap attribute on the th tag), they handle being made fairly narrow well, and they're easy. Make each label cell a header and each field cell a normal cell. And it's a pain, but make sure the labels really are labels and link to their fields, because accessibility matters, even if (perhaps especially if) you're using a table non-semantically.

I'd love to hear about CSS solutions that auto-size the label columns, handle being narrow well, and don't involve 18 hacks to deal with inconsistencies across browsers. I'd be thrilled to see them. But every time I've looked (and that's several), it's still been a gap. A gap that needs filling, IMV, so we can stop doing this without wearing hairshirts.

For anyone reading who doesn't need the labels to the left like that, check out jball's answer for a good-looking, semantic alternative.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • @doublep It works brilliantly on reddit -- guaranteed upvotes to any post that leads off with "I know I'll get downvoted, but". It's like people read it and think "Oh yeah? OH YEAH?! *upvote* TAKE THAT!" – Michael Mrozek May 25 '10 at 21:21
  • 1
    @doublep: Not intended that way, but I understand how you could read it that way. (No call for swearing, though.) But for clarity: I do **not** think anyone who wants to downvote this is a clod. – T.J. Crowder May 25 '10 at 21:22
  • @Michael Mrozek: [offtopic] I know. I developed a rule to never upvote anything "calling" for a downvote, not even when I strongly like it, after seeing this infestation on reddit. –  May 25 '10 at 21:25
  • @doublep and the three (so far!) upvoters on his comment: I've never been on reddit (yes, really) and haven't seen this behavior on SO. I've removed the comments that you took exception to, thanks for letting me know. – T.J. Crowder May 25 '10 at 21:26
  • @Josh: I've looked at Blueprint, and with respect, it fails horribly on the "hacks" front. And the complication front. – T.J. Crowder May 25 '10 at 21:27
  • 9
    @T.J.: It's a matter of principle. Tables are **not** for layout. **Ever**. – Josh K May 25 '10 at 21:27
  • 1
    @Josh: Well, we just disagree there. :-) And fair enough. – T.J. Crowder May 25 '10 at 21:29
  • 2
    +1 for me. The point of the CSS push was not to get rid of all `
    ` s, it was to stop using `
    ` s to render non-tabular layouts. But if you are actually rendering a table... use a `
    `! It's the semantically correct choice.
    – roufamatic May 25 '10 at 21:46
  • 1
    @Josh K: sometimes when desired results meets principle, desired result wins – Matteo Riva May 25 '10 at 21:48
  • 1
    @kemp: I *refuse* to believe that there is a situation where that's the case. – Josh K May 25 '10 at 22:12
  • 1
    As much as I agree on the base principle, I just think that blind absolutism is futile. Fact is that no alternative solution offers *everything* you can do with a table in this case. You could go for a compromise and sacrifice something, but sometimes you're just paid to do what you're told. – Matteo Riva May 25 '10 at 22:53
  • 3
    @Josh: You're right, tables aren't for layout. Except that using tables for forms is perfectly semantic, since forms are tabular data. And as a general point, the term "pure CSS" makes me want to pull my hair out. By definition, a pure CSS website is a nonexistent concept. – DisgruntledGoat May 27 '10 at 13:25
  • @Disgr: Forms are not tabular data. Layout and styles is what's meant by "pure CSS," not that tables are forbidden. – Josh K May 27 '10 at 14:09
  • 5
    @Josh: Not to drag this out (esp. since I originally agreed that this was not a semantic use of tables), but Goat and roufamatic have an interesting point. If I had a series of rows where the `th` contained (say) "First name:" and the following `td` contained "Sam", the next row's `th` was "Last name:" and was followed by `td` = "Samson", that would be tablular data. So why is it not tabular data if the "Sam" and "Samson" are fields? It's an interesting question... – T.J. Crowder May 27 '10 at 15:04
  • @T.J., you should copy your last comment into the answer, as it's a good point. It really opened my eyes ;) – fishbone Nov 21 '12 at 13:17
  • Tables fall short here if one needs to use fieldsets. And AFAIK a legend in a fieldset is the only appropriate/accessible way to name or "label" multiple radio buttons. – Peter V. Mørch Aug 02 '16 at 23:37
19

In terms of usability and if vertical space is not a limiting factor, a list of fields with the label above each field is the quickest to read and fill out, and can be done aesthetically. See many of the usability studies on the web for more info, eg. http://www.lukew.com/resources/articles/web_forms.html

jball
  • 24,791
  • 9
  • 70
  • 92
  • +1 for LukeW, but I'd like to keep labels right-aligned to the left, one of the practices his study advocates for casual users. – Tony the Pony May 25 '10 at 21:30
  • +1 I'm a big fan of these when you can do them, not (only) for semantic markup reasons, but for aesthetic reasons. They just look good. – T.J. Crowder May 25 '10 at 21:57
  • 4
    +1 for referencing "usability studies" on a question where I'd have expected the focus to be on the table-layouts holy war – Richard JP Le Guen May 25 '10 at 22:57
14

I'd like to use definition lists (<dl>) they tends to be semantically correct. A label is defined by an user input. It has sense to me. <dl> expresses semantic contents more accurately than a table.

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

    <dt><label for="email>Email</label></dt>
    <dd><input type="text" id="email" /></dd>
</dl>

Here is an example

By the way they degrade gracefully in all browser, even text-based.

Boris Guéry
  • 47,316
  • 8
  • 52
  • 87
  • this technique never occurred to me... this does seem to be semantically correct, simple, and actually works across browsers... succeeding at all three of those categories makes it the correct answer, IMHO. +1 – rmeador May 25 '10 at 22:35
  • It's an interesting approach. I don't think I'm with you semantically, but it's a matter of opinion. Sadly, it still has the problem that all of the CSS solutions I know have has: The labels won't auto-size, which the OP says she wants. You have to explicitly give them a size (in your "worked example", 33% of 50% of the browser width). – T.J. Crowder May 25 '10 at 22:46
  • Doesn't applying a `display: inline-block` do the trick for auto-sizing ? – Boris Guéry May 26 '10 at 06:03
  • No, I'm afraid that doesn't help. What makes it mostly *seem* to work is the `width:33%`, not the `display: inline-block` (although you do also need that with `dt`s for this). That means that the `dt`s will all be *at least* 33% of the container, but a long label would be longer, resulting in a staggered look. Perhaps not a big deal when you've made the labels so big (~17% of the width of the browser window), but you don't usually have that much room to work with. – T.J. Crowder May 26 '10 at 08:35
  • very clever technique – Vitaliy Terziev Jul 29 '17 at 15:23
5

I think something like this is what i do but also won't autosize to the length of the text but it's cleaner in my opinion

<form>
  <label for="firstName">First Name</label>
  <input type="textfield" name="firstName" />

  <label for="lastName">Last Name</label>
  <input type="textfield" name="lastName" />
</form>

label {
  float:left;
  width:30px;
}

input {
  float:left;
  margin-left:30px;
}
Catfish
  • 18,876
  • 54
  • 209
  • 353
4

The article is a bit old, but I've always found a list apart's advice to be solid: (if you do want to get rid of your tables)

http://www.alistapart.com/articles/prettyaccessibleforms/

quoo
  • 6,237
  • 1
  • 19
  • 36
3

CSS Table Display

From IE8+ you can use CSS Table Display for this:

enter image description here

<!DOCTYPE html>
<html>
<head>
<style>
form > div > label { text-align: right; vertical-align: top }
form { display: table; }
form > div { display: table-row; }
form > div > label,
form > div > textarea,
form > div > input { display: table-cell; }
</style>
</head>
<body>
<form method="post">

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

<div>
<label for="message">Message</label>
<textarea id="message"></textarea>
</div>

<div>
<label for="ssn">Social Security Number</label>
<input type="text" id="ssn"/>
</div>

<div>
<label></label>
<input type="submit" value="Send"/>
</div>

</form>
</body>
</html>
Community
  • 1
  • 1
Jonas
  • 121,568
  • 97
  • 310
  • 388
2

Use a CSS framework like Blueprint and use that to style the forms.

Another trick would be to create virual "columns" with css and float them next to each other. Labels in one column and inputs in another. Put that (both columns) in a div with a large enough width and float the columns the opposite way you want to align them.

Here's some code (because I am creating a form) that will work for basic forms. The only constraint is the large right margin on inputs.

form input, form select
{
    float: right;
    margin-right: 650px;
}
form label
{
    float: right;
    margin-top: 5px;
    margin-right: 10px;
}
form .nofloat
{
    float: none;
    margin: 0;
}
form br
{
    clear: both;
}

And layout like so

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

On top of this small, narrowly written code, there is an entire article related to creating tableless forms in CSS.

Josh K
  • 28,364
  • 20
  • 86
  • 132
0

One problem with tables is the space bug. When you don't use tables you can write your label and input like this:

<label for="foo">Blah <input id="foo" type="text"/></label>

which properly encapsulates the input and the label.

In a table, on the other hand, you get those separated:

<td><label for="foo">Blah</label></td><td><input id="foo" type="text"/></td>

That means the area between the </label> and the <input/> does not respond to mouse clicks.

It's not too bad with plain fields, it's really annoying with radio buttons and checkboxes though (or maybe I'm just being super picky.)

Now, to answer your question: I don't think there is a good way to do formatting of a column in CSS (unless the column width is known--you could obtain that feat with JavaScript...) So T.J. Crowder certainly has an excellent answer.

However, there's one argument for CSS (and forced widths) as in one case I created a very large form that covered the whole screen. All the fields would appear in one screen (As the customer wanted) and the CMS did not output a table. But even though, a table would have been a nightmare simply because all the fields were for many placed in non-aligned columns. That would be quite difficult with a table (lots of rowspan using the table as a grid which would be a table for layout!).


Update:

As per comment below, singe31 says that <input/> cannot be defined within the <label> tag. This is wrong. The HTML 4.01 DTD is easy to read and we see that:

<!ELEMENT LABEL - - (%inline;)* -(LABEL) -- form field label text -->
<!ENTITY % inline "#PCDATA | %fontstyle; | %phrase; | %special; | %formctrl;">
<!ENTITY % formctrl "INPUT | SELECT | TEXTAREA | LABEL | BUTTON">

So in other words an <input/> can appear in a <label> tag. It is perfectly legal.

HTML 5 clearly shows that this is legal in the documentation on w3c here:

http://www.w3.org/html/wg/drafts/html/master/forms.html#the-label-element

Scroll down a bit up to the "Code Example" and you see:

Code Example

For example, on platforms where clicking or pressing a checkbox label checks the checkbox, clicking or pressing the label in the following snippet could trigger the user agent to run synthetic click activation steps on the input element, as if the element itself had been triggered by the user:

<label><input type=checkbox name=lost> Lost</label>

On other platforms, the behavior might be just to focus the control, or do nothing.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
0

Typically, I have found that there are at least some issues when not using Tables for forms. The general things I have not been able to solve:

  • Background-color for fields/inputs is not really possible without a faux background
  • Auto-sizing columns, but I think this is OK
  • Field hover with CSS, you could use JS but Tables can do this with pure CSS

I might be missing a few things, but the most flexible mark-up if you are using CSS is as below:

<div class='form-field'>
   <label>Name</label>
   <input />
</div>

You have issues if you want multiple fields per label section, so you have to introduce another div to hold the inputs (to allow the label to still float left etc):

<div class='form-field'>
   <label>Name</label>

   <div class='form-inputs'>
      <input />
      <input />
   </div>
</div>

With the above mark-up you can achieve very flexible forms, I won't post the CSS as it's very similar to a 2 Column-Layout.

I still need to sit down and try and figure out if pure CSS forms are viable for all occasions but tbh it's very unlikely!

Forms are the worst thing to style using CSS. The only major Cross Browser problems i've had are when styling the FieldSet and Legend elements. No real hacks, but they take some work to look good.

Hux
  • 3,102
  • 1
  • 26
  • 33
  • 1
    How will this align the labels? – Tony the Pony May 25 '10 at 21:56
  • You would float the label left, set its display to inline-block, then add a fixed width. The preferably needs a class on it to make it easier to target with CSS, but the minimum for that class is a left margin equal to the width of the label. The 'form-field' class would have overflow:hidden set to ensure floats are cleared, and the form-inputs would change it slightly for multiple fields. Cheers – Hux May 26 '10 at 09:44
  • This is not an answer to the OPs question, since this requires a fixed width for the label. He writes: "And yes, I'm looking for auto-sizing of the labels" – Peter V. Mørch Aug 02 '16 at 23:48