Taming the select

Of all the form elements in HTML, SELECT is the enfant terrible. It behaves nicely when kept as is, but as soon as we try to teach it some style manners, it'll go ballistic on us. Some browsers allow for border, others allow for a different font, some just don't allow any styling at all.

Partly this is our own fault, we shouldn't try to redesign form elements to blend into the page design. Users know their form elements and know what to do with them, if we change the look of the elements, they'll will have to adapt. Form elements cannot be recognised subconsciously any longer - the user has to find them. It is up to us to decide if we can afford that.

That being true, we will still have to redesign form elements, as the design or the client dictates it, and we want them to pay us. It doesn't hurt mentioning the drawbacks, though.

Styling the select

One of the most designer-annoying features of SELECTs is that they are as wide as their longest option. We cannot force them to have a certain width and make the options wrap. Most browsers will cut off options that are longer than the defined width, something that may render them useless.

Example of how different browsers render a styled select with a fixed width

DOM to the rescue

What we can style nicely are Javascript drop-downs. We can have a link that shows and hides a list of links in an accessible manner (off-left). The only problem is that we make ourselves dependent on Javascript, something we must avoid at all costs.

By using DOM Javascript we can replace the original SELECT with a style-able and accessible drop-down, one that only appears if the browser can hande it.

This script does that. It grabs every SELECT in the document with the class turnintodropdown and replaces it with a styleable CSS dropdown. In essence, it replaces the SELECT with a new DIV. This DIV contains a hidden field has the same name and id as the original SELECT. Furthermore the script creates a list of links that get populated from the OPTION data and a link that shows and hides this list when being clicked on. Clicking one of the links in the list will populate the hidden field with the current value, set it as the text of the "hide and show" link and hide the list.

To see it in action, check the example page.

The style of the drop-down is defined in some classes that get applied via the script as needed:

dropcontainer
defines the parent element of the newly created drop-down parent (a DIV). This needs to be set to "position:relative" to position the drop-down.
trigger
defines the look of the link when then drop-down is hidden.
activetrigger
defines the look of the link when then drop-down is shown.
dropdownhidden
defines the look of the generated drop-down (a UL) when it is hidden.
dropdownvisible
defines the look of the generated drop-down when it is shown.

Check the CSS embedded in the example page for one possible solution.

You can change the class names in the variable section at the top of the script.

But wait, there is more!

Another reoccuring requirement by clients are SELECT navigations.

SELECTs are nice for navigation, they don't take up much screen estate and can be extended and reduced easily without shifting the other content out of the visible screen area.

We can create a perfectly accessible navigation with a select, if only we offer a non-javascript fall-back and a button to submit the form.

Alas, design restrictions and requirements by the client might force for us to get rid of the button. This means that users without Javascript cannot submit the form any longer, which also renders our backend fall-back useless. To navigate, we need to use Javascript called via an onchange handler on the select.

If we use the keyboard for navigation and we tab to the select, some browsers will try to navigate to the next option immediately when we hit arrow down. Experienced keyboard users will know though that you have to hit alt+arrow down first to expand the whole drop-down.

We can point these problems out to the clients, but chances are that we cannot persuade them to comply with our idea of the need for "that ugly button". They saw (or even created) the design and this is exactly how it should look like, for good or for worse.

Reversing the thinking process

We need to ensure that the select without the button only appears when Javascript is available. Furthermore, we don't want to use a fall-back solution on the backend, as it means double maintenance, and we might not be able to offer it.

What we can do is use DOM to take a perfectly accessible and semantically clean navigation like a list of links, and turn it into a SELECT navigation when Javascript is available.

This is also covered by the example script. If you look at the source of the example page, you see that the list of links with the class turnintoselect is turned into a SELECT navigation.

The script was tested on Internet Explorer 5, 5.5, 6, Opera 7.5 and Firefox 0.9 on windows. You can download it together with the demo page and see where else it can perform its magic.