HTML Accessibility

options for optgroup labeling of options

philosoraptor ponders their options: Deque University or Level Access Academy?

An ugly truth is that there are still interoperability issues with some of the native HTML controls and Screen readers. Even though these controls have been around since long before AI came to the rescue of our accessibility asses.

A case in point is the expression of option group labels, AKA (Also Known As) <optgroup label="poot"> What is exposed in the accessibility tree for <select size="1"> and size=>1 still differs in some browsers (i.e. Chrome)

Chrome size=1

<select> exposed as a combobox<optgroup> is not exposed, there is a MenuListPopup containing the 4 menuitem‘s

Snippet from the Accessibility Tree as displayed in the Chrome DevTools Elements Accessibility panel. there is a combobox named 'ingredients 2'. This combobox has several attributes: focusable: true indicates that the combobox can receive keyboard focus. expanded: false suggests that the combobox is currently collapsed. There are four menuitem elements, each representing a selectable option.

Chrome size=>1

<select> exposed as a listbox, each <optgroup> is a group with child options, the <optgroup> label attribute value is used as the accessible name for the group.

screenshot of select size=6 as represented in the accessibility tree in Chrome. ChatGPT says: a listbox widget named "ingredients 1". This listbox is described by several properties: it is focusable (meaning it can be navigated to using a keyboard or other input methods), not multi-selectable (only one option can be selected at a time), and not required (meaning a selection does not have to be made for form completion). Within the listbox, there are two groups. The first group is labeled "vegetables" and contains two options: "tomato" and "carrot". The "tomato" option is focusable but not selected, while the "carrot" option is focusable and is currently selected. The second group within the listbox is labeled "fruits" and also contains two options: "apple" and "pear". Both of these options are focusable but neither is selected. This structured representation indicates a listbox that is organized into categories, allowing users to select one ingredient from a categorized list. The selection state is clearly indicated, showing that 'carrot' is the currently selected option.

Firefox size=1

The representation for the select does expose the optgroup element’s as group‘s in the accessibility tree, unlike Chrome.
a combobox with the name 'ingredients 2' which contains a listbox. Inside the listbox, there is a group labeled 'vegetables' with options 'tomato' and 'carrot', and another group labeled 'fruits' with options 'apple' and 'pear'.

Firefox size=>1

<select> exposed as a listbox, each <optgroup> is a group with child options, the <optgroup> label attribute value is used as the accessible name for the group.

The main container is a listbox with the name 'ingredients 1'. Within this listbox, there are two groups: The first group is labeled 'vegetables'. It contains: A static text element with the text 'vegetables'. Two options: 'tomato' and 'carrot'. The second group is labeled 'fruits'. It contains: A static text element with the text 'fruits'. Two options: 'apple' and 'pear'.

Frigging about

I frigged about with the code, what I wanted was to have JAWS and NVDA to announce the group labels along with the option labels, regardless of the browser and select size and state, in the case of size="1" (on desktop browsers) the select can be operated (using the keyboard) in the collapsed or expanded state. In fact JAWS advises the user to interact with the control in the collapsed state (which is helpful as I would later realise). When a closed select receives focus it announces “combobox, to change the selection use the arrow keys”.

When in the collapsed state, neither JAWS or NVDA announce the group labels. For some reason when in the expanded state in Firefox, JAWS does not announce the group labels, but it does recognize that the option’s are divided into groups…. NVDA does announce as expected.

Collapsed select (combobox) with only the selected option 'pear' displayed.

a dropdown menu with various options grouped under two categories. The categories labels are in bold black text, indicating they are non-selectable headers. The first category is 'vegetables', under which the options 'tomato' and 'carrot' are listed. The second category is 'fruits', with 'apple' and 'pear' as the selectable options. 'Pear' is selected in the dropdown, as indicated by it being highlighted in blue. The dropdown menu is currently expanded, showing all the available options.

Unfortunately even in the case where the group labels are exposed in the Chrome accessibility tree (in the size=>1 case), they are not announced by JAWS or NVDA. I suspect this is due to some property not displayed in the Chrome dev tools accessibility tree, which is causing them to be ignored as they are announced in Firefox, (by NVDA) when the popup is displayed. This is acknowledged by Google acc engineers as a gap in Chrome’s support.

The outcome of the code frigging

I found that I needed to add aria-label to each option which included both the optgroup label and the option label, by doing so the information was announced consistently by NVDA and JAWS  in Chrome and Firefox.

Of course this is not ideal as it requires the addition of ARIA and the duplication of the group label. But the exercise was not about theoretical purity of things working as they should, but about how to convey the information to screen reader users as it is to others.

Using the aria-label on the option element with both the optgroup and option labels as content, provides robust support across browsers and screen readers:

<optgroup label="fruits">
<option aria-label="fruits apple">apple
<option aria-label="fruits pear">pear

Too much effort?

It should be relatively simple to implement via post rendering scripting if necessary, the automated addition of the aria-label‘s using the labels already present in the DOM.

I asked ChatGPT to create a script to do just that, as a proof of concept. It provided me with the following:

javascript:(function() {
document.querySelectorAll('select').forEach(select => {
select.querySelectorAll('optgroup').forEach(optgroup => {
const groupLabel = optgroup.getAttribute('label');
if (groupLabel) {
optgroup.querySelectorAll('option').forEach(option => {
const optionLabel = option.getAttribute('label') || option.textContent;
option.setAttribute('aria-label', `${groupLabel}: ${optionLabel}`);

try it on for size

See the Pen
Using JavaScript to polyfill group labelling support
by steve faulkner (@stevef)
on CodePen.

Further reading

Further listening

One reply on “options for optgroup labeling of options”

Leave a Reply

Your email address will not be published. Required fields are marked *