Making a Better Custom Select Element
In my work as an accessibility consultant, there are some frequent problems I find on people’s websites. One that’s come up a lot recently is that people are making custom select inputs for their forms. I can tell that people are trying to make them accessible, because they’ve added ARIA attributes or visually-hidden instructions for screen reader users. Sometimes they use a plugin which claims to be accessible. And this is great, I love that folks want to do the right thing! But so far I’ve never come across a custom select input which actually meets all of the WCAG AA criteria. Often I recommend to people that they use the native HTML select element instead. Yes, they’re super ugly, but as Scott Jehl shows us in his article Styling a Select Like It’s 2019 they are a lot easier to style than they used to be. They come with a lot of accessibility for free – they’re recognised and announced clearly by all screen reader software, they work reliably and predictably with keyboards and touch, and they look good in high contrast themes. But sometimes, I can’t recommend the select input as a replacement. We want a way for someone to choose an item from a list of options, but it’s more complicated than just that. We want autocomplete options. We want to put images in there, not just text. The optgroup element is ugly, hard to style, and not announced by screen readers. The focus styles are low contrast. I had high hopes for the datalist element, but although it works well with screen readers, it’s no good for people with low vision who zoom or use high contrast themes. Figure 1: a datalist zoomed in by 300% Select inputs are limited in a lot of ways. They’re frustrating to work with when you have something which looks almost like what you want, but is too restricted to be useful. We know we can do better, so we make our own. Let’s work out how to do that while keeping all the accessibility features of the original. Semantic HTML We’ll start with a solid, semantic HTML base. A select input is essentially a text input which restricts the possible answers, so let’s make a standard input. <label for=”custom-select”>User Type</label> <input type=”text” id=”custom-select”> Then we need to show everyone who can see that there are options available, so let’s add an image with an arrow, like the native element. <label for=”custom-select”>User Type</label> <input type=”text” id=”custom-select”> <img src=”https://24ways.org/arrow-down.svg” alt=””> For this input, we’re going to use ARIA attributes to represent the information in the icon, so we’ll give it an empty alt attribute so screen readers don’t announce its filename. Finally, we want a list of options. An unordered list element is a sensible choice here. It also lets screen reader software understand that these bits of text are related to each other as part of a group. <ul class=”custom-select-options”> <li>User</li> <li>Author</li> <li>Editor</li> <li>Manager</li> <li>Administrator</li> </ul> You can dynamically add or remove options from this list whenever you need to. And, unlike our <option> element inside a <select>, we can add whatever we like inside the list item. So if you need images to distinguish between lots of very similar-named objects, or to add supplementary details, you can go right ahead. I’m going to add some extra text to mine, to help explain the differences between the choices. This is a good base to begin with. But it looks nothing like a select input! We want to make sure our sighted users get something they’re familiar with and know how…
Like to keep reading?
This article first appeared on 24ways.org. If you'd like to keep reading, follow the white rabbit.