Styling form fields

As long as I can remember, forms have always been problematic. They need to be short but complete, good looking but not confusing, informative but not cluttered.

These requests are often opposite, especially because designer’s view of those aspects is sometimes…hm, different then client’s.

Basic rules

I believe there is only one basic rule: do not change the overall look of the form elements.

People are used to form elements from the operating system they use. Elements like text fields, checkboxes, drop-down lists and buttons are something people deal with in their usual daily apps, and when they see them on the web, they imidiatelly know what to do with them, i.e. how to fill-in/choose data.

The usual victims are text fields and buttons, as they’re easiest to change.


How many of you recognized that this above is input-awaiting field? Hm, ok. What about your dad? It doesn’t matter if he does too. There’s always people that will be confused. And don’t expect them to call customer service - they are embarassed to not know how to fill-up the form and they will simply leave.

It’s nothing to laugh about. What is obvious to one, is stupid to another and unusable to third. Avoid that.

Another reason against the above is that you can’t style drop-down lists similar to that, so the whole form would look unfinished. Change colours or borders, but don’t remove borders or blend the fields into background.

With this in mind, lets see what we can do.


Form must look acceptable when unstyled, as well as being usable and accessible. W3C specs give us just enough form elements that we barely need something else. You can use fieldset to group elements, legend as heading for such groups and label for field captions.

What else we need? Well, we need to separate the fields. CSS gives us plenty of tools to make the form blocky without extra elements, but since label and form field elements are inline type of elements, in the unstyled version form will look like a mess, especially if you have small helper texts next to some fields:



Please note that password is case-sensitive.


There are few options: use br, div or p. Now, if you use any of the first two, elements will be in their own lines, but will be glued one to another:



Please note that password is case-sensitive.


As known, p is always rendered with one line after it, so it sounds like a good solution. After all, all form elements are of inline type, even if they look blocky. Real problem is that you can’t place another block element inside of paragraph - only inline elements can be nested in. And that is very limiting and I don’t want to backstep sometime in the future when some complicated form comes along the way. So, we are left with the combination of div and br - a bit of extra markup, but one that has no limitations and has good side that extend beyond the mere styling.

Now, lets review the markup rules:

Example form I’m gonna use features all of this - it’s an actual registration form from the commercial web site. Take some time to review the markup before we dive into…


In theory, using CSS and chosen structure, we should be able to style the forms in many various ways. Because of incredible series of browser bugs and/or incomplete support, real life styling options are only few, possibly just one.

I will present several ways, but you’ll see that each one of them has problems in one browser or another. Also note that in each of the examples I remove the brs - their sole purpose of existence is in the unstyled version.

    fieldset br {
    	display: none;

Labels for mandatory fields have class="mandat" which you can style every way you think is appropriate.

There is one little gem in all the styles. If you look at the date of birth group, you will see that each field has its own label, but they are so obvious that we don’t to label each element. Therefore, labels for month and year fields has additional class called removed, styled like this:

    .removed {
    	display: none !important;

Accesibility kept and neatness achieved. Well, I know. Totally correct would be to caption the whole group with paragraph and caption the day field as Day of birth (hidden as other two) - you can take that extra mile if you find it appropriate.

Float labels

This is probably the most used layout in the old, table-based way: line-up field captions in one column, aligned to the right, and place the fields in other column, aligned to the left. Here, it’s done rather easy: convert the labels to blocks, give them average width (I usually go with 10-15em) and float them to the left. Each block will clear the previous one. Check example 1 for full style, and here is the basic stuff:

    fieldset div {
    	clear: both;
    	position: relative;
    label, fieldset div.cr p {
    	margin: 0;
    	display: block;
    	width: 13em;
    	text-align: right;
    	float: left;
    fieldset div.cr label {
    	text-align: left;
    	margin-left: 13em;
    	width: auto;
    	float: none;

Here you see why the div for checkboxes and radio buttons has separate class. In this layout, those elements look best when aligned with the field column. So, for those labels we remove the floating and give them left margin identical to the width of the labels.

Now comes the best part. One of the common requests I mentioned at the beggining is that form should be informative but not cluttered. Some of the fields have such helper texts, but if displayed, they would spoil the neatness of the form. CSS offers the beautiful way of dealing with it; the :hover pseudo-class:

    fieldset div span {
    	display: none;
    fieldset div:hover span {
    	margin-left: 20em;
    	display: block;
    	position: absolute;
    	z-index: 100;
    	float: right;
    * html fieldset div span {
    	display: block;

Last rule is for IE/Win, as it does not support :hover on anything but a elements. I would gladly ignore it, if it wasn’t for the percentage of market it holds. It would be even better if we could do div:focus, since then the helper text would popup even if you don’t use the mouse (i.e. if you tab through the fields)….ah, wishful thinking.

Now, the dark side. This does not work at all in Camino 0.7, due to its severe bug concerning labels. None of rules you apply to label are rendered in Camino, and in this case that’s particularly problematic as fields are placed over the labels and you don’t see them at all. I expect it to be fixed in next version. So, for this style, Camino users: sorry, no joy.

Of course, browser that don’t support :hover (apart from IE) does not display the explanation (mainly Opera 6). Again: sorry, no joy.

Float fieldset

This is my favourite, the best one for liquid layouts. If you have big screen, you will save yourself some scrolling, and if you look at it on small screen (like PDA) the fieldsets would gracefully slide one below the other.

Essential part is to float fieldsets to the left without the specified width. Since the basic idea is to save space, labels will just be blocked, but not floated.

    fieldset {
    	float: left;
    label {
    	display: block;

Very simple and effective. This doesn’t work correctly in Opera 6, which just keeps stacking fieldsets one next to another, going beyond the right viewport edge. Bah. As known, IE5/Mac will render 100% width on all floated elements that don’t have specified width. Bah again. Anoyingly, Opera 7 does the same. Err…lame.

All other styles are just make-up. In this particular example, I tried to move the legend next to the left border, and sort of done it. It works in Opera 7, Safari and Mozilla. IE/Win required some extra nudging to the left, but not quite there. I leave it to you to set left margin 1px more and see what happens. If it isn’t tragic, it would be hilarious.

Block fieldset

This one if good to style with background images on the right side. For the fields and their respective captions, you can use any one of the previous two. Second (as used in the example) is a bit better as you have more room for the image.

Nothing fancy about it, but I included it here to show one particular problem. In IE and Opera, upper edge of the fieldset is lined up with the upper edge of the legend, but the fieldset’s border is drawn aligned to the middle of the legend. Thus, when you apply background color to the fieldset upper border, you get rather ugly rendering. Safari and Mozilla get it right. Be careful.

Fieldset tabs

This is the least usable thing, as only Safari (checked in 1.2 only) get it right. I wanted to move the legend to the left and then with a little script help make it switchable. Well, we will have to wait for something like this. I’m puzzled why Mozilla won’t move the legend beyond the left edge of the fieldset, as you can move it above. Bah…bah… This one is even better to make real tabs (again with some scripting) but the browser support again forces us to wait.

In the end…

…I’m feeling a bit down-hearted. First two layouts are good and usable, but I would be much happier if I could get those tabs to work. With extra markup is doable, but I don’t want to do it since I already have enough extra markup. Maybe in the future…

And with just two layouts, you can’t make that much difference in the world out there, do you..?