Page MenuHomePhabricator

ComboBoxInput- & CapsuleMultiSelectWidget's role=combobox is missing required ARIA children listbox
Closed, ResolvedPublic

Description

ComboBoxInput- & CapsuleMultiSelectWidget's (as of v0.17.9) are featuring role=combobox. This ARIA role requires listbox children,

Related Objects

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

@Prtksxna Not fully sure about good first task as it needs understanding of screen readers as well and that seems more like an intermediate task at least.

Volker_E triaged this task as Medium priority.Dec 15 2016, 5:40 PM

The output should change from:

<div class="oo-ui-comboBoxInputWidget-field">
    <input type="text" tabindex="0" aria-disabled="false" class="oo-ui-inputWidget-input" autocomplete="off" role="combobox" aria-autocomplete="list" id="oojsui-31">
    <span class="oo-ui-comboBoxInputWidget-dropdownButton oo-ui-widget oo-ui-widget-enabled oo-ui-buttonElement oo-ui-buttonElement-framed oo-ui-indicatorElement oo-ui-buttonWidget" aria-disabled="false">
        <a class="oo-ui-buttonElement-button" role="button" tabindex="0" aria-disabled="false" rel="nofollow">
            <span class="oo-ui-iconElement-icon"></span><span class="oo-ui-labelElement-label"></span><span class="oo-ui-indicatorElement-indicator oo-ui-indicator-down"></span>
        </a>
    </span>
</div>
<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-selectWidget oo-ui-selectWidget-depressed oo-ui-clippableElement-clippable oo-ui-menuSelectWidget oo-ui-floatableElement-floatable oo-ui-floatingMenuSelectWidget oo-ui-textInputMenuSelectWidget" aria-disabled="false" role="menu">
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
		<span class="oo-ui-labelElement-label">Option 1</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
		<span class="oo-ui-labelElement-label">Option 2</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
		<span class="oo-ui-labelElement-label">Option 3</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
		<span class="oo-ui-labelElement-label">Option 4</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
		<span class="oo-ui-labelElement-label">Option 5</span>
	</div>
</div>

become:

<div class="oo-ui-comboBoxInputWidget-field">
    <input type="text" tabindex="0" aria-disabled="false" class="oo-ui-inputWidget-input" autocomplete="off" role="combobox" aria-autocomplete="list" id="oojsui-31" **aria-owns="oojsui-32" aria-activedescendant="oojsui-33"**>
    <span class="oo-ui-comboBoxInputWidget-dropdownButton oo-ui-widget oo-ui-widget-enabled oo-ui-buttonElement oo-ui-buttonElement-framed oo-ui-indicatorElement oo-ui-buttonWidget" aria-disabled="false">
        <a class="oo-ui-buttonElement-button" role="button" tabindex="0" aria-disabled="false" rel="nofollow">
            <span class="oo-ui-iconElement-icon"></span><span class="oo-ui-labelElement-label"></span><span class="oo-ui-indicatorElement-indicator oo-ui-indicator-down"></span>
        </a>
    </span>
</div>
<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-selectWidget oo-ui-selectWidget-depressed oo-ui-clippableElement-clippable oo-ui-menuSelectWidget oo-ui-floatableElement-floatable oo-ui-floatingMenuSelectWidget oo-ui-textInputMenuSelectWidget" aria-disabled="false" **role="listbox"  id="oojsui-32"**>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-iconElement oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget oo-ui-optionWidget-selected" aria-disabled="false" tabindex="-1" **role="option"** aria-selected="true" **id="oojsui-33"**>
                <span class="oo-ui-labelElement-label">Option 1</span>
        </div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" **id="oojsui-34"**>
		<span class="oo-ui-labelElement-label">Option 2</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" **id="oojsui-35"**>
		<span class="oo-ui-labelElement-label">Option 3</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" **id="oojsui-36"**>
		<span class="oo-ui-labelElement-label">Option 4</span>
	</div>
	<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" **id="oojsui-37"**>
		<span class="oo-ui-labelElement-label">Option 5</span>
	</div>
</div>

1diff --git a/combobox.html b/combobox.html
2index b75cbd9..971df74 100644
3--- a/combobox.html
4+++ b/combobox.html
5@@ -1,25 +1,25 @@
6-<div class="oo-ui-comboBoxInputWidget-field">
7- <input type="text" tabindex="0" aria-disabled="false" class="oo-ui-inputWidget-input" autocomplete="off" role="combobox" aria-autocomplete="list" id="oojsui-31">
8+</div><div class="oo-ui-comboBoxInputWidget-field">
9+ <input type="text" tabindex="0" aria-disabled="false" class="oo-ui-inputWidget-input" autocomplete="off" role="combobox" aria-autocomplete="list" id="oojsui-31" aria-owns="oojsui-32" aria-activedescendant="oojsui-33">
10 <span class="oo-ui-comboBoxInputWidget-dropdownButton oo-ui-widget oo-ui-widget-enabled oo-ui-buttonElement oo-ui-buttonElement-framed oo-ui-indicatorElement oo-ui-buttonWidget" aria-disabled="false">
11 <a class="oo-ui-buttonElement-button" role="button" tabindex="0" aria-disabled="false" rel="nofollow">
12 <span class="oo-ui-iconElement-icon"></span><span class="oo-ui-labelElement-label"></span><span class="oo-ui-indicatorElement-indicator oo-ui-indicator-down"></span>
13 </a>
14 </span>
15 </div>
16-<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-selectWidget oo-ui-selectWidget-depressed oo-ui-clippableElement-clippable oo-ui-menuSelectWidget oo-ui-floatableElement-floatable oo-ui-floatingMenuSelectWidget oo-ui-textInputMenuSelectWidget" aria-disabled="false" role="menu">
17- <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
18- <span class="oo-ui-labelElement-label">Option 1</span>
19- </div>
20- <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
21+<div class="oo-ui-widget oo-ui-widget-enabled oo-ui-selectWidget oo-ui-selectWidget-depressed oo-ui-clippableElement-clippable oo-ui-menuSelectWidget oo-ui-floatableElement-floatable oo-ui-floatingMenuSelectWidget oo-ui-textInputMenuSelectWidget" aria-disabled="false" role="listbox" id="oojsui-32">
22+ <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-iconElement oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget oo-ui-optionWidget-selected" aria-disabled="false" tabindex="-1" role="option" aria-selected="true" id="oojsui-33">
23+ <span class="oo-ui-labelElement-label">Option 1</span>
24+ </div>
25+ <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" id="oojsui-34">
26 <span class="oo-ui-labelElement-label">Option 2</span>
27 </div>
28- <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
29+ <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" id="oojsui-35">
30 <span class="oo-ui-labelElement-label">Option 3</span>
31 </div>
32- <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
33+ <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" id="oojsui-36">
34 <span class="oo-ui-labelElement-label">Option 4</span>
35 </div>
36- <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="menuitem" aria-selected="false">
37+ <div class="oo-ui-widget oo-ui-widget-enabled oo-ui-labelElement oo-ui-optionWidget oo-ui-decoratedOptionWidget oo-ui-menuOptionWidget" aria-disabled="false" tabindex="-1" role="option" aria-selected="false" id="oojsui-37">
38 <span class="oo-ui-labelElement-label">Option 5</span>
39 </div>
40-</div>
41\ No newline at end of file
42+</div>

So, to recap, we want the following:

  1. The dropdown list must be using role="listbox"/role="option" rather than role="menu"/role="menuitem".
  2. The combobox must be connected to the listbox using aria-owns.
  3. The combobox must be connected to the selected option using aria-activedescendant.

The first looks clear. The second seems only necessary if the listbox is in an overlay (otherwise, the relationship is inferred from the DOM nesting). The third, I'm not convinced about – I'm having trouble making sense of the spec for aria-activedescendant, but it doesn't seem to mean the selected option? Are you sure about this?

Change 348993 had a related patch set uploaded (by Bartosz Dziewoński):
[oojs/ui@master] Do not use role=menu/menuitem for MenuSelectWidget/MenuOptionWidget

https://gerrit.wikimedia.org/r/348993

Change 348993 merged by jenkins-bot:
[oojs/ui@master] Do not use role=menu/menuitem for MenuSelectWidget/MenuOptionWidget

https://gerrit.wikimedia.org/r/348993

Change 349134 had a related patch set uploaded (by Bartosz Dziewoński):
[oojs/ui@master] Set 'aria-owns' for everything with a dropdown list (ARIA combobox)

https://gerrit.wikimedia.org/r/349134

Change 349135 had a related patch set uploaded (by Bartosz Dziewoński):
[oojs/ui@master] SelectWidget/MenuSelectWidget: Maintain 'aria-activedescendant' attribute on focus owner

https://gerrit.wikimedia.org/r/349135

  1. The combobox must be connected to the selected option using aria-activedescendant.

The third, I'm not convinced about – I'm having trouble making sense of the spec for aria-activedescendant, but it doesn't seem to mean the selected option? Are you sure about this?

I see now what confused me – aria-activedescendant is not specific to combobox, but in general it's something that should be set on the currently focussed widget (in ARIA terminology) if the active widget (which roughly means the widget that keyboard actions apply to) is something else. It is also used, for example, on a radiogroup that doesn't allow focussing individual radio buttons: http://oaa-accessibility.org/example/29/ (incidentally, this is also how our RadioSelectWidget works). I ended up implementing this more generally for all kinds of SelectWidgets.

This article was also helpful for me: http://www.ssbbartgroup.com/blog/differences-aria-1-0-1-1-changes-rolecombobox/

Change 349134 merged by jenkins-bot:
[oojs/ui@master] Set aria-owns for everything with a dropdown list (ARIA role=combobox)

https://gerrit.wikimedia.org/r/349134

Change 349135 merged by VolkerE:
[oojs/ui@master] SelectWidget/MenuSelectWidget: Maintain aria-activedescendant attribute on focus owner

https://gerrit.wikimedia.org/r/349135

Volker_E moved this task from Reviewing to OOjs-UI-0.21.2 on the OOUI board.
Volker_E edited projects, added OOUI (OOjs-UI-0.21.2); removed OOUI.
Volker_E removed a project: Patch-For-Review.
Volker_E removed a subscriber: gerritbot.
Volker_E raised the priority of this task from Medium to Needs Triage.Aug 15 2017, 9:53 PM
Volker_E moved this task from Backlog to Done on the UI-Standardization-Kanban board.
Volker_E triaged this task as Medium priority.Aug 16 2017, 6:15 PM

Resetting priority (drag & drop malfunction on “sort by priority” board).

Change 741851 had a related patch set uploaded (by Thiemo Kreuz (WMDE); author: Thiemo Kreuz (WMDE)):

[oojs/ui@master] Fix dead "aria-activedescendant" code path in SelectWidget

https://gerrit.wikimedia.org/r/741851

Change 741851 merged by jenkins-bot:

[oojs/ui@master] Fix dead "aria-activedescendant" code path in SelectWidget

https://gerrit.wikimedia.org/r/741851

Change 935793 had a related patch set uploaded (by Catrope; author: Catrope):

[mediawiki/core@master] Update OOUI to v0.47.2

https://gerrit.wikimedia.org/r/935793

Change 935793 merged by jenkins-bot:

[mediawiki/core@master] Update OOUI to v0.47.3

https://gerrit.wikimedia.org/r/935793