12 February 2008
We all know that people don’t like filling out forms online, including the folks who design and build them. Most good web designers working today know to keep them as concise and painless as possible. A minimalist sign up process on your shiny new web app is sure to produce a higher sign up rate than one that asks for a dozen pieces of irrelevant information.
Sometimes, however, you’ll want to develop a form that truly benefits from a large number of options. Let’s design a search form for a fictional used automobile site. Presenting every option in your database would probably be messy and intimidating. Just one section might look something like this:

An Alternative Presentation
There may be times when keeping all of the available options visible makes the most sense. Let’s assume for the time being, however, that you want to package the search options into a neater display.

Using this technique, we’re able to save valuable screen real-estate and the user is, hopefully, less frightened by all those checkboxes. In addition, you’ll have much more freedom to style your dropdown controls to match the look and feel of your application.
Building the Widget
This technique doesn’t require a fancy graphics treatment. You could easily use vanilla HTML elements and wire up the interaction elements with Javascript (as we’ll discuss below) and you’ll be good to go. However, if you’re wanting that little extra flair, let’s jump into Photoshop (or your graphics editor of choice).
I’ve built my widget to a fixed width with the idea that it’ll be smart enough to grow taller to accommodate longer text. Here’s how the plain widget looked:

And with the dropdown “trigger”:

As I mentioned, we want the widget to be able to expand vertically so that longer text doesn’t dangle outside it. We’ll split our image into top and bottom pieces and stretch the top one out so it’s tall enough to hold the fullest possible amount of text.
Top Piece

Bottom Piece

Be sure you don’t simply resize the image to be tall enough since it will distort your masterpiece. Simply select one horizontal row, copy it, paste it, and use the transform tool to create the “filler” region.
Styling and Wiring
Now it’s time to create the HTML, CSS, and Javascript needed to make your widget come to life. In its most basic form, there is a wrapper container:
<div class="dd_wrapper">
<div class="dd_bottom"></div>
</div>
The dd_wrapper class will contain our top background image and dd_bottom will contain the bottom one.
.dd_wrapper {
color: #fff;
width: 169px;
background: url(../images/dd_top.gif) top left no-repeat;
font-size: 11px;
padding: 11px 30px 10px 14px;
position: relative;
line-height: 1.3em;
min-height: 17px;
}
.dd_bottom {
width: 213px;
height: 18px;
position: absolute;
bottom: -1px;
left: 0;
background: url(../images/dd_bottom.gif) top left no-repeat;
z-index: 0;
}
There’s nothing too fancy going on here. The width of dd_wrapper is accounting for the image width minus the left and right padding (213 – 30 – 14 = 169). The right padding is larger to allow room for the dropdown trigger graphic. The position attribute is set to relative so that we can absolutely position our other elements within in. The dd_bottom class is anchored to the bottom left of the parent container and its width is left at 213px since there is no padding for it. We specify a height of 18px to match that of the bottom image so that it doesn’t collapse and disappear due to having no inner content.
Next, let’s add our dropdown trigger and a span wrapper for our text label.
<div class="dd_wrapper">
<span class="inner">
Engine <span class="light">(6 cylinder, 8 cylinder)</span>
</span>
<a href="#" class="dd_toggle" title="Change">
<img src="../images/dd_toggle.gif" alt="Change" />
</a>
<div class="dd_bottom"></div>
</div>
The inner class will hold our text and the dd_toggle link is positioned on the right hand side.
.dd_wrapper .inner {
position: relative;
z-index: 100;
}
a.dd_toggle {
position: absolute;
top: 11px;
right: 13px;
z-index: 10;
}
.dd_wrapper .light {
color: #a3bfe9;
}
The inner class is relatively positioned so that the z-index rule works properly. These are used to keep the text above the background image of the dd_bottom container.
Now it’s time to add our dropdown panel. It will be hidden by default and the dd_toggle link will call a Javascript function to handle the showing and hiding of the panel.
<div class="dd_wrapper">
<span class="inner">
Engine <span class="light">(6 cylinder, 8 cylinder)</span>
</span>
<a href="#" onclick="toggleDropdown('engine_options');return false;" class="dd_toggle" title="Change"><img src="../images/dd_toggle.gif" alt="Change"/></a>
<div class="dd_bottom"></div>
<div id="engine_options" class="dd_option_panel" style="display:none;">
<p>Select which engine options you are interested in.</p>
<ul>
<li><input type="checkbox" id="engine_4" />
<label for="engine_4">4 cylinder</label>
</li>
<li><input type="checkbox" id="engine_6" checked="checked" />
<label for="engine_6">6 cylinder</label>
</li>
<li><input type="checkbox" id="engine_8" checked="checked" />
<label for="engine_8">8 cylinder</label>
</li>
<li><input type="checkbox" id="engine_10" />
<label for="engine_10">10 cylinder</label>
</li>
<li><input type="checkbox" id="engine_12" />
<label for="engine_12">12 cylinder</label>
</li>
<li><input type="checkbox" id="engine_hybrid" />
<label for="engine_hybrid">Hybrid</label>
</li>
<li><input type="checkbox" id="engine_elec" />
<label for="engine_elec">Electric</label>
</li>
</ul>
<p class="buttons">
<input type="image" src="../images/save_choices.gif" onclick="toggleDropdown('engine_options');return false;"/>
</p>
</div>
</div>
The toggleDropdown() function will toggle the requested panel and it will also ensure that all other panels are hidden. This way, if one panel is open and the user clicks the trigger on another dropdown widget, only the newest panel will appear as open. I am using the Prototype Javascript library here, but this could easily be adapted to any other implementation.
function toggleDropdown(panel)
{
// toggle the requested one
Element.toggle(panel);
// then hide all of the others so that only
// one (at most) is open at a time
$$('body .dd_option_panel').each(function(node){
if (node != $(panel)) {
Element.hide(node);
}
});
}
The Requisite IE Hacks
You can always count on Internet Explorer to keep you on your toes. If you choose to align your dropdown widgets vertically like I have in my example, you’ll notice that the higher dropdown panels render behind the lower widgets. This is due to IE’s z-index implementation that is documented extensively elsewhere. The fix is to wrap each dropdown container with an additional div element whose sole purpose is to force a proper z-index stack.
Also, keep observers may have noticed my use of min-height for the dd_wrapper container. IE6, of course, doesn’t support this attribute but I’ve had success using Dustin Diaz’s Min-Height Fast Hack.
.dd_wrapper {
...
min-height: 17px;
/* IE6 min-height hack: http://www.dustindiaz.com/min-height-fast-hack/ */
height: auto ! important;
height: 17px;
}
<div style="position:relative;z-index:60;">
<div class="dd_wrapper">
...
</div>
</div>
<div style="position:relative;z-index:50;">
<div class="dd_wrapper">
...
</div>
</div>
Final Touches
My example includes a save button that could be used to make an AJAX call. This would be useful if your search updated the results on the fly as search options were changed. If your form was going to be submitted normally, this button could be removed.
Keep in mind that you aren’t limited to checkbox fields in your dropdown panels. You could use radio buttons or anything else. With these types of hidden panels, you will be able to include some additional helper text for your users when it makes sense, but try to keep it short and to the point.
The final thing you’d want to add is some code to handle the updating of the text label when the options are updated. Depending on your implementation, there are various ways to handle this. For example, the result of an AJAX request might determine how the label gets updated. You might want to have your toggleDropdown() function include some logic to update those DOM elements.
My final advice would be to put a little extra thought into making the text labels smart enough to show a concise view of the selections. For example, if your user selects all of the options for Fuel, “Any Fuel” is easier to read (and actually indicates an all-inclusive selection) than “Fuel (Gasoline, Diesel, Alternative)”.
Hopefully this article gives you some ideas that you can incorporate into your next project. The overall idea is quite simple, but there are endless ways that you could expand and improve upon it!


