Note: I'm still learning accessibility, so if you find a flaw in my method, please let me know in the comments below!
Creating custom components i...
For further actions, you may consider blocking this person and/or reporting abuse
A small addition: it could also help to select the correct WAI ARIA roles for the elements, i.e.
Another minor thing: I prefer to use global event handlers (
document.addEventListener(...)
) and filter the event target after their attributes in the handler if I deal with plain vanilla JS; this way, you can even asynchronously add more of those elements and don't need to add events every time you add a custom select box. Obviously, using a toolkit or framework like React, Angular, Vue or similar, you get the events basically for free.As an addition, when recreating some of the native (or more complex) interactive widgets, I find the WAI-ARIA Authoring Practices a great read.
They offer a list of the expected behaviour (for focus, keyboard etc.), as well as the roles and examples of alternative implementations.
iirc,
<select>
in this case falls under a "Listbox" patternFor example, it lists that the
ul
is the one to receive focus, and that theli
items are not tabbable per se, butaria-activedescendant
on theul
marks the candidate selection. There different ways to do things, of course, which is why I like documents there. The discussion of those patterns on Github has also taught me much about accessibility :)Something else that I am reminded of, Scott Jehl from Filament Group had an article a while back about styling the native
select
element. It has some fun stuff:filamentgroup.com/lab/select-css.html
(There was a comment below that mentioned all this replacement seeming tedious, but I find it fascinating how much gets exposed to assistive tehcnologies out of the box)
One more thing I forgot to mention. You should also ensure that the functionality on different screen sizes works. Imagine a country list with 100+ countries and a web app that cuts of at the bottom of the screen. A maximum height of your options list with overflow: auto; will help, but doesn't solve all edge cases.
oh i like the addition of roles here.
Nice article! I have a question... why do you do this invasive customisation?
Why recreating a custom element that behaves like the native one, inteoducing a lot of code, possible bugs, accessibility issues (keyboard navigation and type filter) that is not integrated with the os (like on mobile)? Does this element deserve all of this time just to have a "custom style"? Is this really an accessibility issue?
With a custom select you will completely lose the native datalist element (which is being imemented by all browsers) and you also have to recreate the optgroup element.
I personally prefer my os integrated dropdown let the platform doing the rest.
Regards.
Hi, so normally we would use the native HTML elements and style them appropriately. And if this were a side project, I'd use the browser styling. But often when building a design system, you use custom elements to convey your design language and branding. Thus, custom-styled elements are necessary. That's why I made this!
I think this is true when you add functionalities to the custom component, but it's not true if you are replicating the exact behaviour by just adding a custom dropdown. This is a sort of "personal taste" that cause a lot of issues to developers and designers. In my opinion such element is a critical one and it should deserve the right considerations. Also i don't think a custom drop down will invalidate a design system effectiveness, this means that you should have and use the native select, and then make a new custom component to that add more funcionalities other than datalist, multiple select and optgroup (that coming with the native select).
BTW that's just my opinion. :)
If you add the proper accessibility considerations, screen reader capability with ARIA and keyboard navigation with tabindex, it's just as accessible as the native element. So there's no accessibility benefit over the native element if they're equal in terms of interaction. If I can make a more visually appealing element that adds value and personality to my app, while ensuring compliance with the W3C standards, I'm going to do it.
There are just a lot of things to consider/recreate:
<optgroup>
)All of these thing must be recreated. A lot of effort and possible breaking bugs just to add a custom experience (not better for all) and a custom style. In design systems these things are considere UX breaking.
BTW, i agree with you that this operation must be done if it provide a real value, but at this point, it's not a custom dropdown, it's just a new component. 👍🏻 Cheers.
As soon as you need integrated search, or icons on the options, the native select won't do. And sometimes you can't talk the client out of it.
Maybe this would work well as Web-Component, also.
Yes this is a classic use case for web components, and if you can't make a web component you should just use both native and custom elements. BTW You can already make a native select with search using the <datalist> element that is being implemented.
jsfiddle.net/equinusocio/yj9fb7Lx/4/
This is impressive work! To be honest it makes me think that building an accessible drop-down shouldn't require all this work. I would hope to just need to add a few things here and there. Nonetheless this is next level! Very well done!
Amazingly, I'd been thinking of a way to do this too. I didn't get too far but had a 'proof of concept' build done.
My version has a long way to go though 😅
Great job!! :)
Hi Emma! Thank you for sharing this, it's very useful!
Here's a quick tip I'd like to share.
Instead of writing
document.querySelector()
/document.querySelectorAll()
multiple times, you could do this:I found this article searching for 'accessible custom dropdowns' and was extremely disappointed to find that it seems to be a blatant copy of this article here, morioh.com/p/0993e06398a1 I know development is all about reuse and sharing solutions, but credit should go to the original author for this content
Fun fact, the article you say that THIS article is a copy of, has a link to CodePen at the bottom that... wait for it... links to Emma's CodePen. So this is the OG, the other is the copy.
The Morioh article literally links back to here...
Thanks for sharing this Emma, a few notes from my side I hope you'll find useful.
Setting max-height and opacity makes the options not visible, but this doesn't mean they are not available to ATs or KB users. Try using the tab key (or a screen-reader) and you will see that those no-longer-visible options can still receive focus and are actually there.
You can fix this using
display: none
or settingaria-hidden: true
.I always test my work using a screen-reader (voiceover) and pretty much all the times I am amazed by the amount of extra work I need to do to make it more user-friendly.
Good to see people taking accessibility seriously!
Keep up with the good work
Yay! I love this! I'm going to play around with this as well and I'll let you know what I find!
Yasss thanks!
This is nice work, except, it doesnt appear to work if the list has an overflow-y: scroll and is longer than the height of the div. Also, it seems to scroll the entire page as well as the list. Anyway to prevent that?
Overall nice work. I like your demo but find it odd that the arrow isn't clickable. I can see this being frustrating to disability users who either use a grid overlay to drill down on an item to be able to click on it, or even those with visual impairments that have spotty dark spots (from diabetes or what not) = so having more of the element clickable would be a plus.
dropdown__selected {
}
Well, it seems this works on iOS WebKit.
Awesome! I'll be honest, when I come up with some solutions like this I forget about a11y. Really really important stuff to consider, and you do it beautifully here.
hmmm interesting but what if you want it to be searchable?
That would be a combobox, not a select dropdown.
You can add a search-field as first LI and add some JS to filter out the other LIs by its value.
Hello Emma,
Great post indeed.
Just wanted to know, how would you close the dropdown if we click outside of the dropdown without selecting any option?
Thanks,
Hope this can help :)
If we have 2 or more dropdowns on single page its not working