Skip to: Navigation | Content | Sidebar | Footer

Weblog Entry

Form Elements and ids

March 29, 2005

Finding a balance between label association, validation, and automatic form generation.

So we’re all aware by now that the id attribute is supposed to occur exactly once on a page. You’re not allowed to use more than a single instance of any given id; for that, you’d turn to a class. Multiple classes are no problem, but multiple ids are.

Now if you’ve done you’re homework and you know how to properly apply a label, you’ve probably run into this:

Attribute definitions
for = idref [CS]

This attribute explicitly associates the label being defined with another control. When present, the value of this attribute must be the same as the value of the id attribute of some other control in the same document. When absent, the label being defined is associated with the element’s contents.

This is from the spec and it basically means you should be specifying in your markup that any given label is attached to a specific form element using the for attribute.

There are a few implications from this that are just a little inconvenient. Most importantly, if you’re doing it right, this means that every single input box on a page must have a unique id, for the sake of its label. If you’ve ever had a page that required multiple copies of the same or similar forms, you’ll most likely have run into the validation issues this creates.

The natural tendency is simply to duplicate the forms. If you’re running script which is automating the form creation, you’ll have had to do something like echo "<input type=\"text\" id=\"" . $formControl . $i . "\" />"; — where $i is an incrementing value in the loop. If not, you’d have to do it by hand.

Another issue this raises is that label elements may be associated with exactly one form control on each page. For cases where more than one element should share a common label, the only options are to over-do the labeling and selectively display: none; the undesired labels, or you could also turn to the fieldset and legend combo… neither of which are particularly graceful in their ability to be styled, based on current browser support.

Now, both problems feel more like a design problem than a code problem — in the first case, the benefits of having duplicates of the same form on a page are questionable from a user interaction perspective, and in the second case the desire to not explicitly label a form control seems somewhat user-unfriendly. But let’s recognize that in certain cases, the best choice is an atypical operation. So what then? Extra work for you, that’s what.

Luckily though, the first problem has a fix which is old news, but I’ve only recently discovered simply by reading the spec a little more thoroughly. Implicit association means that instead of this:

<label for="myName">Your Name:</label>
<input type="text" id="myName" />

You can simply do this:

<label>Your Name: <input type="text" /></label>

This solves the first issue nicely, but doesn’t do anything about the second — again according to the spec, you’re only allowed to include a single form element within the label. But at least it’s a start.

Jared says:
March 29, 01h

Please do not shoot me but I only have IE6 here at work.

Was playing around with the due date example.

<fieldset id=”due_date”>
<legend>due date</legend>
<label for=”due_date_month”>month</label><input type=”text” id=”due_date_month” name=”due_date_month”/>
<label for=”due_date_day”>day</label><input type=”text” id=”due_date_day” name=”due_date_day”/>

And a css of

fieldset { border: none; }
legend { height: 1em; }
label { display: none; }
input { margin: -1em; float: left; }
#due_date_month { margin: -1em 0 0 8em; }

makes a rough inline label and 2 input boxes display.

Can’t test this in other browsers at the moment.

geeky says:
March 29, 01h

i’ll go ahead and be the unpopular one to point out that that is one of the nice things about ASP.NET - it creates unique id’s for elements and adds the “for=” attribute to labels automatically.

that said, the rest of the code it generates does suck.

March 29, 01h

I’m sure that the spec says that this:

<label for=”myName”>Your Name:</label>

…is OK, but the implementation is a little buggy. Clicking on the label should focus the associated field - it doesn’t quite work out that way in IE (OK in Firefox, not sure about others).

Some of the examples pointed out above (2 address lines, 3 date inputs) contain different *fields*. I think the LABEL’s intent is to describe the field that it’s asociated with. It sounds like most of these issues would be caught by use of the fieldset and legend elements - if it was supported properly.

March 29, 01h

Sure ASP.NET outputs the label, but you’re only talking about checkboxes and radio buttons right? The radio button/checkbox lists it generates are total crap though, just a big table mess.

David says:
March 29, 01h

Nesting an element into a label has two disadvantages:

- in IE, clicking the label won’t work anymore (yuck)

- you can’t use it with markup like

<dt><label for=”foo”>Foo</label></dt>
<dd><input type=”text” name=”foo” id=”foo” /></dd>

March 29, 01h

I didn’t know you could wrap the label around the elements… sweet. That makes float-based styling a little more straightforward. All you have to do is overflow:auto the label, and then wrap the label text in a span, float it left, and float the textbox right.


Dustin says:
March 29, 01h

what I especially like about the following markup:

<label for=”someId”><input id=”someId” /></label>

is that it keeps the markup down since <input /> fields require some kind of block (or inline-block) level element to wrap around it. You can easily style your forms to look lined up and fancy just styling the label’s to be block elements, floating your input elements to the right, give them a set width, then clearing your label’s.

Jared says:
March 29, 02h

Would using lists be an ok approach to achieve the same effect Dustin’s example gave without nesting the input in the label?

(I am enamored of lists.)

March 29, 02h

Dustin: You don’t even have to include the for= clause if it’s nested. (according to the article…)

And your approach definitely works also. I’m currently fascinated with the overflow:auto business…

March 29, 02h

I first learned about the here:

[Note: That link was a royal pain the publish because of Dave’s naughty word checker. Click on the first search result on the page, “The amazing element”. Sorry about that, but that’s the name of the website :)]

Which was probably published in 2001 or so. Notice his example usage uses the <label> to wrap the input element. It wasn’t until later than I began making my labels stand-alone (rather than wrapping the input element). I’ve grown more partial to *not* wrapping the input element, but with this secret let out on the CSS design community maybe we’ll be seeing a new trick to get the pseudo-table effect that makes it a little easier.

Lach says:
March 29, 03h

“Dustin: You don’t even have to include the for= clause if it’s nested. (according to the article…)”

Mike: You do need to explicitly do the for, even if you nest, if you want ti to work in IE.

Trovster says:
March 29, 05h

The use of implicit form labels is deprecated in WAI WCAG 2.0 in favour of explicit. I’ve had a validator pull me up on this before so had to look it up. The reason they give for deprecating the method is they’re “not supported by user agents and should not be used” �” hmmm…

March 29, 05h

Dave, I’ve never had an issue assigning a unique id to a form element or any page element for that matter. Heck, I often resort to labelling a repetitious block of elements o1, o2, o3, etc. Because in the overall scheme of things, I just need them to be unique.

In database design, this makes perfect sense, each row in a table is assigned a unique id. It’s usually an auto-incrementing integer.

As for associating a label with multiple controls, I think you touched on it when you said that this really tends to be a design issue. We often want to design forms in such a way that makes it easier for a developer to handle on the backend. Breaking down a date field in day, month, year fields is easier to handle than trying to parse what a user enters.

Having Address 1, Address 2 lines is another great example. We do that because we can restrict a user to two lines, and restrict the number of characters per line. “Textareas give users too much control!” So we try and stop them.

In these situations we need to stop and think about what would make the user’s life easier… not ours.

r says:
March 29, 06h

<label>title <input type=”text”></label>
<label>title <input type=”radio” value=”1”> Yes</label> <label><input type=”radio” value=”0”> No</label>

I thought everyone did it this way. The pain (and bytes) of writing all those IDs and FORs is far too much.

IE is broken, but 1) too bad, no tiny added convenience for you (my approach), or 2) you can use a js onload script to make it work. Everyone else is fine.

As an aside, I don’t think labels are even 5% as useful as “useability experts” seem to think they are. Most websites don’t have them, so why would any rational user waste a click clicking on a title that most likely won’t do anything? (And missing by 5mm+ isn’t going to happen often.) I know I never do. Probably the only people who do are developers checking if other developers have used labels :-)

March 29, 07h

beautiful! I am actually in the middle of this problem at the moment, am going to have to tackle and finish it tomorrow, now I know the angle I’ll pursue. Thanks Dave!

Paul van Steenoven says:
March 29, 10h

I myself have problems nesting a input inside a label because the way i style forms right now is giving a label a fixed width where you can give your form a nice indented horizontal layout.

Nesting a input would leave you no way to fix the width, other then that putting the contents of a label inside a span or a div and I absolutely not want that.

Ill go with the old way and using unique ID’s and to be honest if you have to much unique ID’s in your form maybe its more time to go through your forms and ways to split a form in several steps.



March 29, 11h

How does this affect the use of radio buttons?

I’m involved in a project right now which requires a labeled set of radio buttons. Using the name attribute, it is possible to group them, but giving them all the same id causes validation issues.

This is probably a stupid question, but it’s one that I haven’t found a satisfying solution to.

March 29, 11h

I must confess I’m finding it hard to think of times when a label should be associated with more than one form control, with the exception of radio buttons and check boxes (which definitely should be enclosed in a fieldset).

Isofarro says:
March 29, 11h

If you want to go down the “hidden labels” route, consider the following writeup:

We’re in the same minefield at the moment, I’m morbidly fascinated by how differently Mozilla and IE handle legend styling. At this rate, hidden labels looks to be the practical approach.

At least I’m not alone now ;-)

Isofarro says:
March 29, 11h

Cameron Walters asks: “How does this affect the use of radio buttons? .. I’m involved in a project right now which requires a labeled set of radio buttons. Using the name attribute, it is possible to group them, but giving them all the same id causes validation issues.”

Each radio button would require its own unique label anyway - one for each unique option text. The problem left over is how to associate the “main text” label with all three. Semantically that’s what fieldset and legend are for.

Each radio button requires its own unique id (unless you use implicit labelling of each radio button) - so you are right, they can’t share ids. Here’s a good piece for radio buttons:

One wrinkle reading the HTML specification carefully - it is possible to have more than one label applying to one particular field. But not one label applying to multiple fields.

Hope that helps.

Zac says:
March 29, 12h

As Isofarro said, even in the case of checkboxes and radio buttons, a label tag should be used to display the value of _each_ individual form element — not a group of elements. One probable reason for this (among others) is clickability issues; if you click on a label tag that surrounds 4 checkboxes, which checkbox should become checked?

If you’re trying to label a group of form elements (and aren’t comfortable with the styling quirks of the legend tag), you might as well use a or <div> to label the entire group. Using multiple identical label tags in that fashion doesn’t gain you any additional semantic or usability value, and is probably just more trouble than it’s worth.

Dave S. says:
March 29, 12h

Simon — “Address Line 1”, “Address Line 2” vs. “Address”. Although my inclination would be to use different wording and thus require both labels anyway, but that’s one example for you.

Scott says:
March 29, 12h

Simon: One of the classic “multiple inputs requiring one label” scenarios would be a date input, e.g.:

<label>Due Date
<select id=”selMonth”>
<option value=”1”>January</option>
<option value=”2”>February</option>

<input type=”text” id=”txtDay” />
<input type=”text” id=”txtYear” />

The label should apply to all three inputs, except that according to the specs, it can’t. Why would you ask for a date like that, instead of just nicely asking the user to enter the date in “mm/dd/yyyy” format? That’s what the client wanted. Or maybe you want to allow the user to enter a non-specific date like just the year, or the month and year.

I typically take the hidden label approach, and do something like this:

<div class=”label”>Due Date
<label for=”selMonth” class=”hidden”>Month Due</label>
<select id=”selMonth”>…</select>
<label for=”txtDay” class=”hidden”>Day Due</label>
<input type=”text” id=”txtDay” />
<label for=”txtYear” class=”hidden”>Year Due</label>
<input type=”text” id=”txtYear” />

You can guess the basics of the CSS - the label and .label selectors get the same styling, and the .hidden class gets hidden.

March 29, 12h

This article reminds me of what I was lamenting yesterday. When are things in the world of web design/development going to “get better”?

How long have we waited for (insert aggravating fix or missing feature)?

Why is it that a good 10 years after the appearence of the web, we have so many irritating and aggravating interface issues with browsers and CSS/HTML?

Not to derail this thread because the label issue is a valid one. It just highlights something that for me has been very frustrating lately as I struggle with these issues on a daily basis.

My personal opinion is that things are moving way too slowly. The W3C is ineffective, in my view. It seems to have become a beauracratic nightmare. The only thing that has given our industry a kick in the pants lately has been FireFox - and it’s effects have been great, but not far reaching enough by a long shot.

End rant. We now return to stupid problems with labels that ought not to be.

Zac says:
March 29, 12h

Tom – I definitely understand your frustration, but this <label> issue seems to be the fault of certain browsers’ inability to style <fieldset> and <legend> consistently. The W3C provided the those tags for exactly this purpose – and they work well, provided that you’re willing to sacrifice a precise layout in some browsers. As annoying as this can be (I’ve torn my hair out over it in the past), it seems to me that the spec isn’t the problem, the browser implementation is.

Jared says:
March 29, 12h

Is there a real reason for wanting the id for a radio/checkbox to be the same for the whole group?

What possible effect can be reached by id’ing them all the same that can’t be reached when giving them their proper ids?

Only thing I can think of would be javascript validation but if you are autogenerating the form why can’t you autogenerate code?

I must say I am a tad confused why this,

[INPUT type=”radio” name=”gender” value=”Male” /] Male[BR]

would be preferred over this

[LABEL for=”gender_male”]Male[/LABEL][INPUT type=”radio” id=”gender_male” name=”gender” value=”male” /]

Or is there something wrong with the later example? I would think that “Male” is the label for this radio button.

March 29, 12h

Very nice, I was struggling with how to approach the multiple labels for a single input element (not literally a single element, but a date represented by 3 drop-downs). The hidden label answers this problem.

The fieldset implementation *is* buggy and frustrating, but hopefully by this time next year everyone will have it better sorted out. Even Mozilla has bugs some bugs to fix:

March 30, 01h

Another related problem the duplication of is ‘id’ and ‘name’:

For a label to ‘work’ it needs linking to the id of the control:

<label for=’username’>Username</label> <input type=’text’ id=’username’/>

All well and good, but if you submit the form the value wont be passed because you haven’t specified a ‘name’:

<label for=’username’>Username</label> <input type=’text’ name=’username’/>

…except now, the label doesn’t ‘work’.

The fix is to have both an id AND a name:

<label for=’username’>Username</label> <input type=’text’ id=’username’ name=’username’/>

…which is unnecessary duplicated code in my book.

Oliver says:
March 30, 01h

I think it’s that upon click the label, the element the label is for will be focused. Since not more than one element can be focused at the same time in a browser, the label cannot be applied to more than one element, otherwise the browser would crash or something.

goetsu says:
March 30, 03h

for information this solution (surroundding the input with label)cause some bug on the old version of netscape like between 6 and 7 and maybe on mozilla too.

March 30, 05h

Richard@Home: the importance of having a separate name and id attribute is that they serve two different purposes. The name attribute is to identify the value to a server when a form is submitted; the id is to identify the element in the client.

Consider the following:

<label for=”redCheckbox”>Red</label><input type=”checkbox” value=”red” name=”colour” id=”redCheckbox”>
<label for=”greenCheckbox”>Green</label><input type=”checkbox” value=”green” name=”colour” id=”greenCheckbox”>
<label for=”blueCheckbox”>Blue</label><input type=”checkbox” value=”blue” name=”colour” id=”blueCheckbox”>

In this case, the labels are attached by the client to the checkboxes via their id. Assume that the user checks “red” and “green”. When the form is submitted, two values with the name “colour” will be sent to the server, one with value “red” and one with “green”; assuming a GET, we have

In the more likely case of a server-side form handler, most systems will automagically convert the same-name elements into an array (or equivalent collection) which can be iterated over.

Thus there is no redundancy: just a clear separation of attributes having relevance to the server, and those having relevance to the client. I may be wrong, but I believe this was the reason the id attribute was introduced with HTML 4; in HTML 3.2, all we had was a name.

March 30, 06h

The issue with using the label wrapped around the input fix is that sometimes you need the label and the input element to be in different divs or table cells and the label tag doesn’t work accross different block level elements.

March 30, 11h

I’ve been nesting inputs inside labels for a while now, but then I add a label:hover rule to give it a subtle background highlight.

I’m sure it’s not for everyone (and only works in “happy” browsers), but I like the effect.

March 30, 11h

I coworker of mine will commonly use a label element within a fieldset’s legend, so I tried out something funky: an input inside a label inside a legend, with a further label as a sibling to the input (child of previously mentioned label) and that all validates.

I am curious about what implications this has for form semantics and consequently accessibility.

Interesting find Dave; a very useful design tool that fixes a lot of past problems I’ve experienced. I’ll be implementing straight away on my projects. Thanks!

Dustin says:
March 30, 12h

a bit late…
but yea, like Lach said, you need the for attr for this to work in IE. The great thing is though, you’re still saving up on a lot of markup. Even the CSS is cut down quite a bit from what you might think of what it would take to look like it was nested in a table.

March 31, 04h

Nick Fitzsimons said:
> In the more likely case of a server-side form handler, most systems will automagically convert the same-name elements into an array (or equivalent collection) which can be iterated over. <

You can properly a form control to be an array adding square brackets after the name. Thus, the code would become:
<label for=”redCheckbox”>Red</label><input type=”checkbox” value=”red” name=”colour[]” id=”redCheckbox”>
<label for=”greenCheckbox”>Green</label><input type=”checkbox” value=”green” name=”colour[]” id=”greenCheckbox”>
<label for=”blueCheckbox”>Blue</label><input type=”checkbox” value=”blue” name=”colour[]” id=”blueCheckbox”>

To differentiate form elements with the rest of the content I use a prefix, usually form_. I find it a bit silly that form controls use the same sort of ‘id’ as the rest of an (X)HTML page. This is clearly a bad decision on the W3C’s behalf and should be altered in following recommendations.

Lach says:
March 31, 07h


“You can properly a form control to be an array adding square brackets after the name.”

That’s a hack for PHP. In my, admittedly limited experience, most server side processors are smart enough to put multiple values in an array without needing [] to prompt them.

March 31, 08h

This is a little off topic, but what do you think of the way that XForms decided to handle label elements? In XForms, the label element is a child of the input element. (and a required one at that)

<input ref=”name”>

This makes it easy because the element is always associated with the propper input without need for unique id for each control.

Of course, since no browsers support XForms, or the pseudo-elements to style it, it’s somewhat of a moot point. We’ll just have to wait and see what will be possible when we can actually use these features outside of a controlled enviroment.

c. s. says:
April 01, 03h

Since so many are bringing up the subject of saved bytes for nesting elements inside labels, I figured I’d nitpick the sample PHP code:

echo “<input type="text" id="” . $formControl . $i . “" />”;

echo ‘<input type=”text” id=”’ . $formControl . $i . ‘” />’;
sprintf(‘<input type=”text” id=”%s%s” />’, $formControl, $i);

By using single quotes, you don’t have to escape any double quotes inside the string, but you do if you use single quotes. You only need to use double quotes for strings if you’re using “special characters” like newlines or otherwise want PHP to process the contents of the string (e.g. echo “We’ve looped through this piece of code $count times.\nAre we there yet?!\n\n”);).

All those escaped quotes decrease readability in addition to adding extra bytes for no reason.

“for information this solution (surroundding the input with label)cause some bug on the old version of netscape like between 6 and 7 and maybe on mozilla too.”

The only issue with labels that I’m aware of with NS 6/7 and the corresponding Mozilla builds causes floated labels to disappear. I personally used for/id because I was unaware of nesting when I encountered the bug. And no, adding display: block or any other CSS trickery could bring it back (other than removing the float, of course).

Jason says:
April 27, 12h

I really like your work around. It saves some html code and in my opinion makes everything mroe readable.

Don’t you just love how the W3C can keep churning out new great technologies like XForms that won’t be supported till 10 years later… and then-so only partially by internet explorer.

Anyways… One problem I have run into with checkbox group arrays is accessing them in javascript. if you have:

<input type=”checkbox” value=”green” name=”color[]” id=”id1”>
<input type=”checkbox” value=”blue” name=”color[]” id=”id2”>

you cannot say: document.forms[0].color since “color” isn’t the actual name… its “color[]” so you need to do somthing like document.forms[0].elements[“color[]”] in order to get at the slement