diff --git a/content/patterns/listbox/examples/css/listbox-actions.css b/content/patterns/listbox/examples/css/listbox-actions.css index b2e95bdfb..447fe59ec 100644 --- a/content/patterns/listbox/examples/css/listbox-actions.css +++ b/content/patterns/listbox/examples/css/listbox-actions.css @@ -1,81 +1,155 @@ +.hide-actions-button { + display: none !important; +} + [role="option"] span.actions { - display: none; + display: none; } [role="option"]:hover span.actions, [role="listbox"]:focus [role="option"].focused span.actions { - position: absolute; - right: 0.5em; - display: flex; - justify-content: center; - align-items: center; - gap: 3px; - top: -3px; + position: absolute; + right: 0.5em; + display: flex; + justify-content: center; + align-items: center; + gap: 3px; +} + +.contentRow { + display: flex; + width: 100%; +} + +.contentColumn { + flex: 1; + padding: 1rem; + background-color: #f0f0f0; +} + +.listbox-area h3 { + font-weight: normal; + color: var(--text); + font-family: sans-serif; + font-size: 1em; + padding-bottom: 3px; +} + +.listbox-area ul { + padding-top: 5px; +} + +.detailPanel { + margin: 1em 0 0; + padding-top: 7px; + padding-left: 10px; + min-height: 18em; + border: 1px solid #aaa; + background: white; +} + +.detailPanel.is-hidden { + display: none; } button.actionButton { - display: inline-block; - border-radius: 5px; - text-align: center; - color: #222428; - font-size: 14px; - line-height: 1.5em; - margin-right: 0.25em; - background-color: buttonface; - padding-right: 5px; - margin-top: -3px; + display: inline-block; + border-radius: 5px; + text-align: center; + color: #222428; + font-size: 14px; + line-height: 1.5em; + margin-right: 0.25em; + background-color: buttonface; + padding-right: 5px; + margin-top: -3px; } button.actionButton::before { - display: flex; - justify-content: center; - align-items: center; - height: 32px; - width: 15px; + display: flex; + justify-content: center; + align-items: center; + height: 32px; + width: 15px; } button.uparrow::before { - content: "↑" / ""; + content: "↑" / ""; } button.downarrow::before { - content: "↓" / ""; + content: "↓" / ""; } button.favorite[aria-pressed="true"]::before { - content: "★" / ""; + content: "★" / ""; } button.favorite:not([aria-pressed])::before, button.favorite[aria-pressed="false"]::before { - content: "☆" / ""; + content: "☆" / ""; } button.delete::before { - content: "🗑" / ""; + content: "🗑️" / ""; +} + +[role="option"] { + position: relative; + display: block; + line-height: 1.8em; + cursor: pointer; + margin: 2px 2px 2px 8px; + padding: 2px 1em 2px 2.5em; } [role="option"] button:hover, .focusedActionButton { - background-color: rgb(226 239 225); - color: black !important; - white-space: pre; - outline: #036 solid 3px !important; - border-color: rgb(0 90 156); + background-color: rgb(226 239 225); + color: black !important; + white-space: pre; + outline: #036 solid 3px !important; + border-color: rgb(0 90 156); } -.listbox-area { - display: block; - padding: 20px; - border-width: 1px; - border-style: solid; - border-color: rgb(170 170 170); - border-image: initial; - border-radius: 4px; - background: rgb(238 238 238); - max-width: 20em; +[role="option"][aria-selected="true"] span.favoriteOptionIndication::before { + position: absolute; + left: 1.2em; + content: ""; } -.hide-actions-button { - display: none; +[role="option"][aria-actions] span.favoriteOptionIndication::before { + position: absolute; + left: 1.4em; + content: "☆" / "Favorite"; +} + +[role="option"][aria-actions].js-favoriteIndication span.favoriteOptionIndication::before { + position: absolute; + left: 1.4em; + content: "★" / "Favorite"; } + +[role="option"][aria-actions] span.js-selection::before { + position: absolute; + left: 0.2em; + content: "☐" / "Favorite"; +} + +[role="option"][aria-selected="true"] span.js-selection::before { + position: absolute; + left: 0.2em; + content: "☑" / "Favorite"; +} + +.listbox-area { + display: block; + padding: 20px; + border-width: 1px; + border-style: solid; + border-color: rgb(170 170 170); + border-image: initial; + border-radius: 4px; + background: rgb(238 238 238); + max-width: 20em; +} \ No newline at end of file diff --git a/content/patterns/listbox/examples/js/listbox-actions.js b/content/patterns/listbox/examples/js/listbox-actions.js index b028ab088..0b0617be0 100644 --- a/content/patterns/listbox/examples/js/listbox-actions.js +++ b/content/patterns/listbox/examples/js/listbox-actions.js @@ -55,16 +55,16 @@ aria.ListboxActions = class ListboxActions { this.activeDescendant = this.listboxActionsNode.getAttribute( 'aria-activedescendant' ); - this.registerActionsEvents(); this.listboxOptionArray = Array.from( this.listboxActionsNode.querySelectorAll('[role="option"]') ); - this.handleItemChange = function () {}; + this.handleItemChange = function () { }; this.listboxItemCurrent = null; this.listboxActiveOption = null; this.listboxCurrentItemActionsButtons = []; this.listboxCurrentOptionIndex = -1; this.listboxItemsWithAriaActionsArray = []; + this.registerActionsEvents(); } registerActionsEvents() { @@ -77,7 +77,7 @@ aria.ListboxActions = class ListboxActions { this.onSetCurrentActiveOptionForListbox.bind(this) ); let actionButtons = this.listboxActionsNode.querySelectorAll( - 'button:not(.hide-actions-button)' + 'button:not(.hide-actions-button),.js-favorite' ); for (let i = 0; i < actionButtons.length; i++) { actionButtons[i].addEventListener( @@ -85,6 +85,15 @@ aria.ListboxActions = class ListboxActions { this.onCheckClickItemActions.bind(this) ); } + let selectionCheckbox = this.listboxActionsNode.querySelectorAll( + '.js-selection' + ); + for (let i = 0; i < selectionCheckbox.length; i++) { + selectionCheckbox[i].addEventListener('click', (event) => { + event.currentTarget.closest('[role="option"]').click(); + }); + } + } /** * @description @@ -134,92 +143,55 @@ aria.ListboxActions = class ListboxActions { } /** * @description - * Updates necessary attributes to ensure the up arrow does not appear if the option is the first. - * Updates necessary attributes to ensure that the down arrow does not appear if the option is the last. + * Updates necessary attributes to ensure the up does not appear if an option is the first in the list. + * Updates necessary attributes to ensure the down does not appear if an option is the last in the list. */ - prepareToMoveUpItems() { - if (!this.activeDescendant) { - return; - } - const currentItem = this.listboxItemCurrent; - const previousItem = currentItem.previousElementSibling; + updateArrowUpDownItems() { this.listboxOptionArray = Array.from( this.listboxActionsNode.querySelectorAll('[role="option"]') ); - if (previousItem) { - /** Hides the down arrow for item moved to the end of list and shows arrow on item moved up from bottom */ - if ( - this.listboxOptionArray.indexOf(previousItem) == - this.listboxOptionArray.length - 2 - ) { - currentItem - .querySelector('.downarrow') - .classList.remove('hide-actions-button'); - currentItem + for (let i = 0; i < this.listboxOptionArray.length; i++) { + let option = this.listboxOptionArray[i]; + if (this.listboxOptionArray.indexOf(option) == this.listboxOptionArray.length - 1) { + option .querySelector('.downarrow') .classList.remove('focusedActionButton'); - previousItem + option .querySelector('.downarrow') .classList.add('hide-actions-button'); - this.activeDescendant = currentItem.id; - } - /** Hides the up arrow for item moved to the top of list and shows arrow on item moved down from top */ - if (this.listboxOptionArray.indexOf(previousItem) == 1) { - currentItem - .querySelector('.uparrow') - .classList.add('hide-actions-button'); - currentItem + } else if (this.listboxOptionArray.indexOf(option) == 0) { + option .querySelector('.uparrow') .classList.remove('focusedActionButton'); - previousItem + option + .querySelector('.uparrow') + .classList.add('hide-actions-button'); + } else { + option + .querySelector('.downarrow') + .classList.remove('hide-actions-button'); + option .querySelector('.uparrow') .classList.remove('hide-actions-button'); - this.setActiveDescendant(currentItem); } } } /** * @description - * Updates necessary attributes to ensure the down arrow does not appear if the option is the last option. - * Updates necessary attributes to ensure that the up arrow does not appear if the options is first option. + * Key press listener + * Updates the details panel when listbox selection is made + * @param currentOption */ - prepareToMoveDownItems() { - if (!this.activeDescendant) { - return; - } - var currentItem = this.listboxItemCurrent; - var nextItem = currentItem.nextElementSibling; - this.listboxOptionArray = Array.from( - this.listboxActionsNode.querySelectorAll('[role="option"]') - ); - if (nextItem) { - /** Hides the down arrow for item moved to the end of list and shows arrow on item moved up from bottom */ - if ( - this.listboxOptionArray.indexOf(nextItem) == - this.listboxOptionArray.length - 1 - ) { - currentItem - .querySelector('.downarrow') - .classList.add('hide-actions-button'); - currentItem - .querySelector('.downarrow') - .classList.remove('focusedActionButton'); - nextItem - .querySelector('.downarrow') - .classList.remove('hide-actions-button'); - this.setActiveDescendant(currentItem); - } - /** Hides the up arrow for item moved to the top of list and shows arrow on item moved down from top */ - if (this.listboxOptionArray.indexOf(nextItem) == 2) { - currentItem - .querySelector('.uparrow') - .classList.remove('hide-actions-button'); - currentItem - .querySelector('.uparrow') - .classList.remove('focusedActionButton'); - nextItem.querySelector('.uparrow').classList.add('hide-actions-button'); - this.activeDescendant = currentItem.id; + populateDetails(currentOption) { + if (currentOption.role == "option") { + let detailPanels = document.querySelectorAll('.js-detailPanel'); + for (let i = 0; i < detailPanels.length; i++) { + if (!detailPanels[i].classList.contains('is-hidden')) { + detailPanels[i].classList.add('is-hidden'); + } } + let detailPanel = document.querySelector('#' + currentOption.id + '_detail_panel'); + detailPanel.classList.toggle('is-hidden'); } } @@ -260,8 +232,15 @@ aria.ListboxActions = class ListboxActions { } this.setActiveDescendant(this.listboxItemsWithAriaActionsArray[0]); this.Listbox.focusItem(this.listboxOptionArray[0]); + this.updateArrowUpDownItems(); break; + case 'js-favorite': case 'favorite': + //If the favorite icon was clicked and is the activeButton instead of the action button, + //convert the activeButton to the action button and continue processing + if (activeButton.classList.contains('js-favorite')) { + activeButton = activeButton.closest('[role="option"]').querySelector('.favorite'); + } activeButton.setAttribute( 'aria-pressed', activeButton.ariaPressed && activeButton.ariaPressed == 'true' @@ -272,28 +251,34 @@ aria.ListboxActions = class ListboxActions { activeButton.ariaPressed == 'true' ? 'favorite' : 'unfavorited', [activeOption] ); - if (activeOption.querySelector('.js-favoriteIndication')) { - activeOption.querySelector('.js-favoriteIndication').innerText = + activeOption.classList.toggle('js-favoriteIndication'); + if (activeOption.classList.contains('js-favoriteIndication')) { + activeOption.querySelector('.offscreen').innerText = activeButton.ariaPressed == 'true' ? 'Favorite' : ''; } break; case 'uparrow': - this.prepareToMoveUpItems(); this.Listbox.moveUpItems(); + this.updateArrowUpDownItems(); break; case 'downarrow': - this.prepareToMoveDownItems(); this.Listbox.moveDownItems(); + this.updateArrowUpDownItems(); break; } this.Listbox.updateScroll(); } + /** + * @description + * Handles the action buttons key press events + * @param event + * The key press event + */ onCheckKeyPressActions(event) { let listitemCurrentItemActionsButtonPosition, listboxCurrentItemActionsButton; this.listboxItemCurrent = this.listboxActionsNode.querySelector('.focused'); this.listboxCurrentOptionIndex = this.listboxOptionArray.indexOf(this.listboxItemCurrent); - console.log(this.listboxCurrentOptionIndex); this.activeDescendant = this.listboxActionsNode.getAttribute( 'aria-activedescendant' ); @@ -321,6 +306,7 @@ aria.ListboxActions = class ListboxActions { this.listboxItemCurrent, this.listboxCurrentItemActionsButtons.map((node) => node.id).join(' ') ); + this.populateDetails(this.listboxItemCurrent); break; case 'ArrowLeft': case 'ArrowRight': @@ -347,13 +333,13 @@ aria.ListboxActions = class ListboxActions { if (listitemCurrentItemActionsButtonPosition > 0) { this.focusActionsItem( this.listboxCurrentItemActionsButtons[ - listitemCurrentItemActionsButtonPosition - 1 + listitemCurrentItemActionsButtonPosition - 1 ] ); } else { this.defocusActionsItem( this.listboxCurrentItemActionsButtons[ - listitemCurrentItemActionsButtonPosition + listitemCurrentItemActionsButtonPosition ] ); this.setActiveDescendant(this.listboxItemCurrent); @@ -367,13 +353,13 @@ aria.ListboxActions = class ListboxActions { ) { this.focusActionsItem( this.listboxCurrentItemActionsButtons[ - listitemCurrentItemActionsButtonPosition + 1 + listitemCurrentItemActionsButtonPosition + 1 ] ); } else { this.focusActionsItem( this.listboxCurrentItemActionsButtons[ - listitemCurrentItemActionsButtonPosition + listitemCurrentItemActionsButtonPosition ] ); } @@ -387,8 +373,6 @@ aria.ListboxActions = class ListboxActions { : event.currentTarget ); break; - default: - break; } } /** @@ -398,7 +382,7 @@ aria.ListboxActions = class ListboxActions { * The click event */ onCheckClickItemActions(event) { - event.preventDefault(); + event.stopImmediatePropagation(); event.key = 'Enter'; let previousFocus = this.listboxActionsNode.querySelectorAll('.focused'); let prev; @@ -426,6 +410,7 @@ aria.ListboxActions = class ListboxActions { } } } + this.populateDetails(event.target); } }; window.addEventListener('load', function () { diff --git a/content/patterns/listbox/examples/listbox-actions.html b/content/patterns/listbox/examples/listbox-actions.html new file mode 100644 index 000000000..8635bf099 --- /dev/null +++ b/content/patterns/listbox/examples/listbox-actions.html @@ -0,0 +1,449 @@ + + + + + + + Experimental Example of Scrollable Listbox with Actions on Options + + + + + + + + + + + + + + + + + + +
+

Experimental Example of Scrollable Listbox with Actions on Options

+ +
+

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:

+ +
+ +
+
+

Example

+
+ +
Last change:
+
+

+ 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. +

+ +
+
+ +
+
+ Bucket List: +
    +
  • + + + Complete an Iron Man + + + + + + +
  • +
  • + + + Climb Everest + + + + + + +
  • +
  • + + + Learn archery + + + + + + +
  • +
  • + + + Train a guide dog + + + + + + +
  • +
  • + + + Build an airplane + + + + + + +
  • +
+
+
+
+ +
+
+

Details:

+ + + + + +
+
+
+
+ +
+ +
+

Accessibility Features

+ +
+ +
+

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. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyFunction
TabMoves focus into and out of the listbox.
Down ArrowMoves focus to and selects the next option.
Up ArrowMoves focus to and selects the previous option.
Right Arrow +
    +
  • If an option has focus, moves focus to the first action button.
  • +
  • If an action button has focus, moves focus to the next action button for the current option.
  • +
  • If the last action button has focus, does nothing.
  • +
+
Left Arrow +
    +
  • If any action button except for the first action button has focus, moves focus to the previous + action button for the current option.
  • +
  • If the first action button has focus, moves focus to the current option.
  • +
  • If an option has focus, does nothing.
  • +
+
HomeMoves focus to and selects the first option.
EndMoves focus to and selects the last option.
Printable Characters +
    +
  • Type a character: focus moves to the next item with a name that starts with the typed character. +
  • +
  • Type multiple characters in rapid succession: focus moves to the next item with a name that starts + with the string of characters typed.
  • +
+
+
+ +
+

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. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleAttributeElementUsage
listboxulIdentifies the focusable element that has listbox behaviors and contains the listbox options.
aria-labelledby="ID_REF"ulRefers to the element containing the listbox label.
tabindex="0"ulIncludes the listbox in the page tab sequence.
aria-activedescendant="ID_REF"ul +
    +
  • When an option in the listbox is visually indicated as having keyboard focus, refers to that option. +
  • +
  • Enables assistive technologies to know which element the application regards as focused while DOM + focus remains on the listbox element.
  • +
  • When navigation keys, such as Down Arrow, are pressed, the JavaScript changes the value. +
  • +
  • + For more information about this focus management technique, see + Managing + Focus in Composites Using aria-activedescendant. +
  • +
+
optionliIdentifies each selectable element containing the name of an option.
aria-selected="true"li +
    +
  • Indicates that the option is selected.
  • +
  • Applied to the element with role option that is visually styled as selected.
  • +
  • The option with this attribute is always the same as the option that is referenced by + aria-activedescendant because it is a single-select listbox where selection follows focus.
  • +
+
aria-actions=""li +
    +
  • Indicates to assistive technologies that the option will have actions available on focus or hover, + enabling the assistive technology to focus the element to gain access to the actions.
  • +
  • Applied to all elements with role option when they are not visually styled as selected and are not + referenced by aria-activedescendant.
  • +
+
aria-actions="ID_REFS"li +
    +
  • Specifies the ID attributes of the action buttons that are associated with the option.
  • +
  • Applied to the element with role option that is visually styled as selected and is referenced by + aria-activedescendant.
  • +
+
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

+ +
+ +
+

HTML Source Code

+

To copy the following HTML code, please open it in CodePen.

+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/content/patterns/listbox/examples/listbox-scrollable-actions.html b/content/patterns/listbox/examples/listbox-scrollable-actions.html deleted file mode 100644 index cbb8b8bd8..000000000 --- a/content/patterns/listbox/examples/listbox-scrollable-actions.html +++ /dev/null @@ -1,561 +0,0 @@ - - - - - - Experimental Example of Scrollable Listbox with Actions on Options - - - - - - - - - - - - - - - - - -
-

Experimental Example of Scrollable Listbox with Actions on Options

- -
-

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:

- -
- -
-
-

Example

-
- -
Last change:
-
-

Choose your favorite transuranic element (actinide or transactinide).

-
-
- Transuranium elements: -
    -
  • - - None -
  • -
  • - - Neptunium - - - - - - -
  • -
  • - - Plutonium - - - - - - -
  • -
  • - - Americium - - - - - - -
  • -
  • - - Curium - - - - - - -
  • -
  • - - Berkelium - - - - - - -
  • -
  • - - Californium - - - - - - -
  • -
  • - - Einsteinium - - - - - - -
  • -
  • - - Fermium - - - - - - -
  • -
  • - - Mendelevium - - - - - - -
  • -
  • - - Nobelium - - - - - - -
  • -
  • - - Lawrencium - - - - - - -
  • -
  • - - Rutherfordium - - - - - - -
  • -
  • - - Dubnium - - - - - - -
  • -
  • - - Seaborgium - - - - - - -
  • -
  • - - Bohrium - - - - - - -
  • -
  • - - Hassium - - - - - - -
  • -
  • - - Meitnerium - - - - - - -
  • -
  • - - Darmstadtium - - - - - - -
  • -
  • - - Roentgenium - - - - - - -
  • -
  • - - Copernicium - - - - - - -
  • -
  • - - Nihonium - - - - - - -
  • -
  • - - Flerovium - - - - - - -
  • -
  • - - Moscovium - - - - - - -
  • -
  • - - Livermorium - - - - - - -
  • -
  • - - Tennessine - - - - - - -
  • -
  • - - Oganesson - - - - - - -
  • -
-
-
-
- -
- -
-

Accessibility Features

- -
- -
-

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. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
KeyFunction
TabMoves focus into and out of the listbox.
Down ArrowMoves focus to and selects the next option.
Up ArrowMoves focus to and selects the previous option.
Right Arrow -
    -
  • If an option has focus, moves focus to the first action button.
  • -
  • If an action button has focus, moves focus to the next action button for the current option.
  • -
  • If the last action button has focus, does nothing.
  • -
-
Left Arrow -
    -
  • If any action button except for the first action button has focus, moves focus to the previous action button for the current option.
  • -
  • If the first action button has focus, moves focus to the current option.
  • -
  • If an option has focus, does nothing.
  • -
-
HomeMoves focus to and selects the first option.
EndMoves focus to and selects the last option.
Printable Characters -
    -
  • Type a character: focus moves to the next item with a name that starts with the typed character.
  • -
  • Type multiple characters in rapid succession: focus moves to the next item with a name that starts with the string of characters typed.
  • -
-
-
- -
-

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. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RoleAttributeElementUsage
listboxulIdentifies the focusable element that has listbox behaviors and contains the listbox options.
aria-labelledby="ID_REF"ulRefers to the element containing the listbox label.
tabindex="0"ulIncludes the listbox in the page tab sequence.
aria-activedescendant="ID_REF"ul -
    -
  • When an option in the listbox is visually indicated as having keyboard focus, refers to that option.
  • -
  • Enables assistive technologies to know which element the application regards as focused while DOM focus remains on the listbox element.
  • -
  • When navigation keys, such as Down Arrow, are pressed, the JavaScript changes the value.
  • -
  • - For more information about this focus management technique, see - Managing Focus in Composites Using aria-activedescendant. -
  • -
-
optionliIdentifies each selectable element containing the name of an option.
aria-selected="true"li -
    -
  • Indicates that the option is selected.
  • -
  • Applied to the element with role option that is visually styled as selected.
  • -
  • The option with this attribute is always the same as the option that is referenced by aria-activedescendant because it is a single-select listbox where selection follows focus.
  • -
-
aria-actions=""li -
    -
  • Indicates to assistive technologies that the option will have actions available on focus or hover, enabling the assistive technology to focus the element to gain access to the actions.
  • -
  • Applied to all elements with role option when they are not visually styled as selected and are not referenced by aria-activedescendant.
  • -
-
aria-actions="ID_REFS"li -
    -
  • Specifies the ID attributes of the action buttons that are associated with the option.
  • -
  • Applied to the element with role option that is visually styled as selected and is referenced by aria-activedescendant.
  • -
-
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

- -
- -
-

HTML Source Code

-

To copy the following HTML code, please open it in CodePen.

- -
- - -
-
- -