HTML Forms: The Right Way(s)
I recently stumbled upon a Reddit discussion thread on the proper way to write an HTML form. First, there is no one right way to code an HTML form. Well, I should say there is no one right way to code an HTML form assuming you are using semantic and accessible markup. Here are several methods I use (or have seen others use) when writing HTML forms.
Method 1: Semantic Nirvana
<form> <fieldset> <legend>Legend Name</legend> <label for="name">Name</label> <input type="text" name="name" /> </fieldset> </form>
This example is self-explanatory and employees the recommended form elements provided by HTML. The form element contains a fieldset with a legend. The fieldset contains a label and an associated input field. This method is the purest state of a semantic HTML form, and I encourage you to implement this structure whenever possible. However, if your design requires more structural flexibility, I encourage you to explore the definition list approach.
Method 2: Definition List
<form> <fieldset> <dl> <dt><label for="name">Name</label></dt> <dd><input type="text" name="name" /></dd> </dl> </fieldset> </form>
This example encapsulates the form and its elements within the context of a definition list. One could argue the semantic accuracy of this approach, but I believe there is some semantic truth to this scenario. A definition term (the "Name") is defined by the user input. This method also remains accessible to assistive technologies by providing a label for the associated input field. Label's allow assistive technologies to associate the label with a form input field. Label's also provide a larger, clickable "focus" area for a form field; when a user clicks on a label, the associated form input field is focused. This method also degrades nicely in text-only web browsers or hand-held devices.
I often use this method when I create forms with labels to the left of their associated input fields, similar to the Sign Up form on Campaign Monitor's website (see Figure A). The DT elements are floated left and assigned a common width. The DD fields are floated right and assigned a common width. The DT fields will clear any previous DT or DD elements using CSS.
One might consider ordered or unordered lists to accomplish this same structure. However, such an approach would require the markup developer to attach custom class meta information to each LI element to indicate which LI element contains the label and which the form input field. I believe the definition list provides more accurate semantics without additional meta information.
Overall, I prefer this method when I require semantics and design flexibility. This method provides plenty of elements to work with out of the box: form, dl, dt, dd, label, and input. CSS developers will have plenty to work with without extraneous markup.
Method 3: Paragraphs galore!
<form> <fieldset> <p> <label for="name">Name</label><br /> <input type="text" name="name" /> </p> </fieldset> </form>
I mention this method only because I see many developers abuse it too often. This method encapsulate a label and its input field within a paragraph. The result is a pleasant visual separation when rendered in most desktop web browsers like Firefox, Safari, or Internet Explorer. However, the good ends there. This method is semantically flawed; a form and its elements are not a series of paragraphs. Also, one should not mix markup with presentation (as this method does). After all, not everyone uses visual web browsers (Google bots and screen readers come to mind).
Method 4: What about columns?
Many HTML forms are presented in a column layout. This is an example where aesthetics take precedence over semantics. Which is fine. Semantics are only rules, and rules can be broken, right? In this case, I encourage you to at least try to maintain some form of semantic value.
Method 4a: Use DIVs with appropriate class meta data
One method to implement a column layout is to use DIVs.
<form> <fieldset> <legend>Legend Name</legend> <div class="left-column"> <label for="name">Name</label> <input type="text" name="name" /> </div> <div class="middle-column"> <label for="email">Email</label> <input type="text" name="email" /> </div> <div class="right-column"> <label for="phone">Phone</label> <input type="text" name="phone" /> </div> </fieldset> </form>
Each DIV may be floated left to simulate columns, and the class attributes convey the intended semantics.
Method 4b: Tables: Those are bad, right?
Tables are great, assuming you use them to display tabular data. Tables were given a bad reputation when print designers first started developing websites in the late 90s and early 2000s. Print designers used tables for lack of better layout tools.
If you have no other option, one might argue that a form could be a table (try not to smirk when you explain this to your resident web standards evangelist). Such a form may look like this:
<form> <fieldset> <table border="0"> <thead> <tr> <th>Column 1</th> <th>Column 2</th> <th>Column 3</th> </tr> </thead> <tbody> <tr> <td> <label for="one">One</label> <input type="text" name="one" /> </td> <td> <label for="two">Two</label> <input type="text" name="two" /> </td> <td> <label for="three">Three</label> <input type="text" name="three" /> </td> </tr> </tbody> </table> </fieldset> </form>
At this point, the form markup is becoming convoluted and less semantic. Consider this method a last resort, and only if you require a form with multiple columns.
So which method do I choose?
There are many more ways to write HTML forms. As I said before, there is no one right way to write HTML forms. If your form is structured with semantic and accessible markup, you can't go wrong. For further reading on this subject, I strongly encourage you to pick up a copy of "Web Standards Solutions: The Markup and Style Handbook" by Dan Cederholm (Apress, 2004; ISBN 1590593812).