Experimental Example of Scrollable Listbox with Actions on Options
Read This First
Experimental content! Do not use except for new standards development purposes. Please read below to understand why.
This is an experimental implementation of potential future techniques that may not yet be supported by web standards.
- This example may include ARIA, HTML, CSS, or other code that is not yet included in a final web standard specification.
- Experimental content is published in the APG only to facilitate discussion, gather feedback, and support testing of new features in browsers and assistive technologies.
- There may be little or no support for this example in any or most browser and assistive technology combinations.
- The ARIA and Assistive Technologies Project is developing measurements of assistive technology support for APG examples.
About This Experimental Example
This is an experimental implementation of the draft specification of the
aria-actions attribute.
The aria-actions property enables an element to reference one or more interactive elements that can
be activated to perform an action on the referencing element.
In this example, each option element in the listbox references several buttons that
perform actions on the option.
The relationship provided by aria-actions enables an assistive technology to both communicate the
availability of the action button and provide a command for activating the button while focus is on the tab.
The following example implementation of the Listbox Pattern demonstrates a
scrollable single-select listbox widget.
This widget is functionally similar to an HTML select input where the size attribute
has a value greater than one.
This example also demonstrates how to provide buttons that provide contextual actions for each item in the list.
Each option has an associated set of four actions that enable users to move an option up or down,
favorite it, or remove it from the list.
The contextual actions are provided by buttons that appear on hover or focus.
The buttons are referenced by aria-actions specified on the option element, which
enables them to be discovered and activated by an assistive technology user while focus is on the
option.
Similar examples include:
- Scrollable Listbox Example: Single-select listbox that scrolls to
reveal more options, similar to HTML
selectwithsizeattribute greater than one. - Example Listboxes with Rearrangeable Options: Examples of both single-select and multi-select listboxes with accompanying toolbars where options can be added, moved, and removed.
- Listbox Example with Grouped Options: Single-select listbox with grouped
options, similar to an HTML
selectwithoptgroupchildren.
Example
Plan your bucket list: Select an item to view or edit its details. Flag it for follow up if you need to do more research. You can also rank or delete items.
- https://github.com/w3c/aria-practices/pull/3400
- Readonly edit like color picker and file tree view so it can be accessible and screen reader users could tab to it
- Don't have selection follow focus. Require space bar or enter key. Other listbox examples follow the implicit selection model so having it require an enter.
- Make the star next to the checkbox the action and remove the button from the actions buttons
- Complete an Iron Man
- Climb Everest
- Learn archery
- Train a guide dog
- Build an airplane
Details:
Accessibility Features
-
Because this listbox implementation is scrollable and manages which option is focused by using
aria-activedescendant, the JavaScript must ensure the focused option is visible.
So, when a keyboard or pointer event changes the option referenced by
aria-activedescendant, if the referenced option is not fully visible, the JavaScript scrolls the listbox to position the option in view. -
To enhance perceivability when operating the listbox, visual keyboard focus and hover are styled using the CSS
:hoverand:focuspseudo-classes:- To help people with visual impairments identify the listbox as an interactive element, the cursor is changed to a pointer when hovering over the list.
- To make it easier to distinguish the selected listbox option from other options, selection creates a 2 pixel border above and below the option.
Keyboard Support
The example listbox on this page implements the following keyboard interface. Other variations and options for the keyboard interface are described in the Keyboard Interaction section of the Listbox Pattern.
NOTE: When visual focus is on an option in this listbox implementation, DOM focus remains on
the listbox element and the value of aria-activedescendant on the listbox refers to the descendant
option that is visually indicated as focused.
Where the following descriptions of keyboard commands mention focus, they are referring to the visual focus
indicator, not DOM focus.
For more information about this focus management technique, see
Managing
Focus in Composites Using aria-activedescendant.
| Key | Function |
|---|---|
| Tab | Moves focus into and out of the listbox. |
| Down Arrow | Moves focus to and selects the next option. |
| Up Arrow | Moves focus to and selects the previous option. |
| Right Arrow |
|
| Left Arrow |
|
| Home | Moves focus to and selects the first option. |
| End | Moves focus to and selects the last option. |
| Printable Characters |
|
Role, Property, State, and Tabindex Attributes
The example listbox on this page implements the following ARIA roles, states, and properties. Information about other ways of applying ARIA roles, states, and properties is available in the Roles, States, and Properties section of the Listbox Pattern.
| Role | Attribute | Element | Usage |
|---|---|---|---|
listbox |
ul |
Identifies the focusable element that has listbox behaviors and contains the listbox options. | |
aria-labelledby="ID_REF" |
ul |
Refers to the element containing the listbox label. | |
tabindex="0" |
ul |
Includes the listbox in the page tab sequence. | |
aria-activedescendant="ID_REF" |
ul |
|
|
option |
li |
Identifies each selectable element containing the name of an option. | |
aria-selected="true" |
li |
|
|
aria-actions="" |
li |
|
|
aria-actions="ID_REFS" |
li |
|
|
aria-hidden="true" |
span |
Removes the character entity used for the check mark icon from the accessibility tree to prevent it from being included in the accessible name of the option. |
JavaScript and CSS Source Code
- CSS: listbox.css
- JavaScript: listbox.js, listbox-actions.js
HTML Source Code
To copy the following HTML code, please open it in CodePen.
<p>
Plan your bucket list: Select an item to view or edit its details. Flag it for follow up if you need to do
more research. You can also rank or delete items.
</p>
<ul>
<li>
https://github.com/w3c/aria-practices/pull/3400
<ul>
<li>
Readonly edit like color picker and file tree view so it can be accessible and screen reader users could tab to it
</li>
<li>
Don't have selection follow focus. Require space bar or enter key. Other listbox examples follow the implicit selection model so having it require an enter.
</li>
<li>
Make the star next to the checkbox the action and remove the button from the actions buttons
</li>
</ul>
</li>
</ul>
<div class="contentRow">
<div class="contentColumn">
<div class="listbox-area">
<div>
<span id="ss_elem" class="listbox-label">
Bucket List:
</span>
<ul id="ss_elem_list"
tabindex="0"
role="listbox"
aria-labelledby="ss_elem">
<li id="ss_elem_IronMan"
role="option"
aria-controls="ss_elem_IronMan_detail_panel"
aria-details="ss_elem_IronMan_detail_panel"
aria-actions="">
<span class="js-selection" aria-hidden="true"></span>
<button aria-label="favorite"
tabindex="-1"
class="js-favorite favorite favoriteOptionIndication actionButton"
id="ss_elem_IronMan_favorite"></button>
Complete an Iron Man
<span class="offscreen favoriteIndication"></span>
<span class="actions">
<button aria-label="move up"
tabindex="-1"
class="uparrow actionButton hide-actions-button"
id="ss_elem_IronMan_uparrow"></button>
<button aria-label="move down"
tabindex="-1"
class="downarrow actionButton"
id="ss_elem_IronMan_downarrow"></button>
<button aria-label="delete"
tabindex="-1"
class="delete actionButton"
id="ss_elem_IronMan_delete"></button>
</span>
</li>
<li id="ss_elem_Everest"
role="option"
aria-controls="ss_elem_Everest_detail_panel"
aria-actions="">
<span class="js-selection" aria-hidden="true"></span>
<button aria-label="favorite"
tabindex="-1"
class="js-favorite favorite favoriteOptionIndication actionButton"
id="ss_elem_Everest_favorite"></button>
Climb Everest
<span class="offscreen favoriteIndication"></span>
<span class="actions">
<button aria-label="move up"
tabindex="-1"
class="uparrow actionButton"
id="ss_elem_Everest_uparrow"></button>
<button aria-label="move down"
tabindex="-1"
class="downarrow actionButton"
id="ss_elem_Everest_downarrow"></button>
<button aria-label="delete"
tabindex="-1"
class="delete actionButton"
id="ss_elem_Everest_delete"></button>
</span>
</li>
<li id="ss_elem_Archery"
role="option"
aria-controls="ss_elem_Archery_detail_panel"
aria-actions="">
<span class="js-selection" aria-hidden="true"></span>
<button aria-label="favorite"
tabindex="-1"
class="js-favorite favorite favoriteOptionIndication actionButton"
id="ss_elem_Archery_favorite"></button>
Learn archery
<span class="offscreen favoriteIndication"></span>
<span class="actions">
<button aria-label="move up"
tabindex="-1"
class="uparrow actionButton"
id="ss_elem_Archery_uparrow"></button>
<button aria-label="move down"
tabindex="-1"
class="downarrow actionButton"
id="ss_elem_Archery_downarrow"></button>
<button aria-label="delete"
tabindex="-1"
class="delete actionButton"
id="ss_elem_Archery_delete"></button>
</span>
</li>
<li id="ss_elem_GuideDog"
role="option"
aria-controls="ss_elem_GuideDog_detail_panel"
aria-actions="">
<span class="js-selection" aria-hidden="true"></span>
<button aria-label="favorite"
tabindex="-1"
class="js-favorite favorite favoriteOptionIndication actionButton"
id="ss_elem_GuideDog_favorite"></button>
Train a guide dog
<span class="offscreen favoriteIndication"></span>
<span class="actions">
<button aria-label="move up"
tabindex="-1"
class="uparrow actionButton"
id="ss_elem_GuideDog_uparrow"></button>
<button aria-label="move down"
tabindex="-1"
class="downarrow actionButton"
id="ss_elem_GuideDog_downarrow"></button>
<button aria-label="delete"
tabindex="-1"
class="delete actionButton"
id="ss_elem_GuideDog_delete"></button>
</span>
</li>
<li id="ss_elem_Airplane"
role="option"
aria-controls="ss_elem_Airplane_detail_panel"
aria-actions="">
<span class="js-selection" aria-hidden="true"></span>
<button aria-label="favorite"
tabindex="-1"
class="js-favorite favorite favoriteOptionIndication actionButton"
id="ss_elem_Airplane_favorite"></button>
Build an airplane
<span class="offscreen favoriteIndication"></span>
<span class="actions">
<button aria-label="move up"
tabindex="-1"
class="uparrow actionButton"
id="ss_elem_Airplane_uparrow"></button>
<button aria-label="move down"
tabindex="-1"
class="downarrow actionButton hide-actions-button"
id="ss_elem_Airplane_downarrow"></button>
<button aria-label="delete"
tabindex="-1"
class="delete actionButton"
id="ss_elem_Airplane_delete"></button>
</span>
</li>
</ul>
</div>
</div>
</div>
<div class="contentColumn">
<div class="listbox-area">
<h3>
Details:
</h3>
<div id="ss_elem_IronMan_detail_panel" class="js-detailPanel detailPanel is-hidden">
Iron Man content goes here.
</div>
<div id="ss_elem_Everest_detail_panel" class="js-detailPanel detailPanel is-hidden">
Climbing Mount Everest content goes here.
</div>
<div id="ss_elem_Archery_detail_panel" class="js-detailPanel detailPanel is-hidden">
Archery content goes here.
</div>
<div id="ss_elem_GuideDog_detail_panel" class="js-detailPanel detailPanel is-hidden">
Gide dog training content goes here.
</div>
<div id="ss_elem_Airplane_detail_panel" class="js-detailPanel detailPanel is-hidden">
Airplane Building content goes here.
</div>
</div>
</div>
</div>