An accessible, keyboard friendly custom select menu
I’ve always been wary of styling form elements too much. Possible usability and accessibility issues, browser quirks, and the fact that the CSS specification does not define form control styling are the main reasons.
With that said, sometimes you have to do things you don’t really want to. Like styling select
elements, which I’ve recently had to find a way to do. There are quite a few workarounds for doing this out there. However, most of the ones I looked at replace the select
element with a bunch of links which changes semantics and behaviour a bit too much for my tastes. I couldn’t find any implementation that I was completely happy with, so I took the best one I could find and tweaked it.
In my book, a custom select
element should:
- keep working the same way as a native
select
element - not confuse keyboard users
- not introduce extra text or change semantics for screen reader users
- be built on progressive enhancement
The safest way to do this is to only style the closed select
element and leave styling of the opened state to the browser, which is what Alen Grakalic does in Custom styling of the SELECT elements. So I decided to use that as a starting point and add some refinements to make it work the way I want it to.
The clever trick Alen uses is to make the real select
element completely transparent and place it on top of a span
element that you can style exactly the way you want to. When the select
menu is opened, the options are displayed the way the browser normally displays them. No, the options aren’t custom styled, but in most cases it’s the appearance of the closed select
element that is most important to the design. YMMV.
Some of the changes I’ve made are these:
- The focus and hover states are styled for easier keyboard navigation
- The fake select is updated when you use the arrow keys to step through the options of a closed select element in Firefox
- The fake select is hidden from screen readers with
aria-hidden
to avoid repetition - A container
div
element is inserted around theselect
element to make positioning of the fake select independent of the surrounding markup - The custom select will adjust to the width of its parent, removing the need to give it a fixed width
- If the text of the selected
option
is too wide for the custom select, it will be clipped withtext-overflow:ellipsis
The entire script (which is written as a jQuery plugin) is available in jquery.customselect.js. You can find some examples of the script in action on the Accessible, keyboard friendly custom select menu demo page.
Of course the custom select element needs a bit of CSS as well. It isn’t particularly complicated, so please view source on the demo page for a closer look.
To make the fake select flexible (both horizontally and vertically), I’ve used a background image that is both taller and wider than I expect a select to become. In this case it’s just a gradient with a separator and an arrow, so you could likely do the whole thing with CSS3 and avoid using any images at all if you wanted to.
As for browser support, I have tested this without noticing any issues in IE7+ and the latest versions of Firefox, Safari (OS X and iOS), Chrome and Opera. In IE7 and IE8 the fake select doesn’t get rounded corners or drop shadows, but it’s possible to work around that by using CSS3 PIE. Or you could just live with different rendering in those browsers. If you really, really have to you could probably make this work in IE6 as well, though I decided to stop at IE7.
With JavaScript off, the custom select element becomes a standard select element rendered with each browser’s default styling.
And finally a reminder: Just because you can, doesn’t mean you should.
- Previous post: No more conditional comments in IE10
- Next post: JavaScript-created markup also needs to be semantic and accessible