Custom elements and accessibility
Asked Answered
C

2

10

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?

Collateral answered 13/5, 2014 at 6:38 Comment(0)
S
1

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.

Smote answered 17/8, 2014 at 18:26 Comment(1)
Although this would work in terms of accessibility, it goes against my goals of encapsulation (because a select element that is not part of the provided HTML would appear in the light DOM). Secondly, if I tried the same with a more complicated widget (e.g. a listbox whose options contain more than some text), I would have to replace the select element with a custom-made aria-conforming widget, which just means that I would have to double my x-listbox.Collateral
D
0

In the markup provided, x-option is in the light DOM, not the shadow DOM, so it can be referred to by id. To avoid polluting the id namespace, I generate a random id, which is set when the component loads but can be replaced. This way I can refer to the element by id whether or not the component user has set an id on it. Wrapping each option in a div seems unnecessary and likely to cause issues. Also, if the options are in a <slot />, it's simply not possible.

Dutra answered 25/5, 2021 at 13:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.