I'd like to implement a listbox widget using the current web components specs. Moreover, the resulting listbox should conform to the ARIA standard. Instantiating the listbox widget should be as simple as:
<x-listbox>
<x-option>Option 1</x-option>
<x-option>Option 2</x-option>
</x-listbox>
For purposes of cleanliness and encapsulation, everything else should be rendered in shadow dom. To implement this widget, two custom elements, <x-listbox>
and <x-option>
are registered. The top-level element of the shadow dom of <x-listbox>
is a <div>
that carries the role=listbox
and the aria-activedescendent
attributes for accessibility (I don't want these attributes on the <x-listbox>
element because they are implementation details.)
In order for aria-activedescendent
to work, one needs ids on the option elements. Putting ids directly on the <x-option>
elements won't work out of two reasons: Firstly, it would pollute the id namespace of the document that uses the listbox widget. Secondly and even more importantly, ids do not work across shadow boundaries (which is one purpose of the shadow dom), so the ids of the options have to live in the same shadow dom as the <div>
with the aria-activedescendent
attribute.
A solution for this would be to surround each <x-option>
that is rendered as content inside the shadow dom of <x-listbox>
with another <div>
(belonging to that shadow dom), on which an id can be put.
My question is: Is this the right way to go and how to implement this using the custom element and shadow dom web apis?
Your probably should better implement this by creating an select
element (using JavaScript). This should ensure screen readers recognize this correctly as an input for selecting a value/values from a list.
Add an select
element like this below your <x-listbox>
element:
<select class="only-screenreader">
<option>Option 1</option>
<option>Option 2</option>
</select>
Then add aria-hidden="true"
to your custom <x-listbox>
element.
Finally apply CSS to make the screenreader select element invisible.
.only-screenreader {
position:absolute;
left:-10000px;
top:auto;
width:1px;
height:1px;
overflow:hidden;
}
That's my approach but maybe there's a better one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With