Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(list): address accessibility console error #920

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ exports[`gux-action-button renders 1`] = `
</gux-button-slot>
</div>
<div class="gux-list-container" slot="popup">
<gux-list role="list">
<gux-list role="list" tabindex="-1">
<template shadowrootmode="open">
<span aria-hidden="true" tabindex="-1"></span>
<slot></slot>
</template>
<slot></slot>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ exports[`gux-context-menu renders 1`] = `
</gux-button-slot>
</div>
<div class="gux-list-container" slot="popup">
<gux-list role="list">
<gux-list role="list" tabindex="-1">
<template shadowrootmode="open">
<span aria-hidden="true" tabindex="-1"></span>
<slot></slot>
</template>
<slot></slot>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Component, Element, h, Host, JSX, Listen, Prop } from '@stencil/core';

import { getClosestElement } from '@utils/dom/get-closest-element';
import { Component, Element, h, Host, JSX, Prop } from '@stencil/core';

/**
* @slot - text
Expand All @@ -18,27 +16,6 @@ export class GuxListItem {
@Prop()
disabled: boolean = false;

@Listen('mouseup')
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daragh-king-genesys I am tagging you here because you seem to be the one who added this code. Can you remember if this code has any utility that I may be overlooking? I am removing it because it is causing unwanted focus behavior after my changes in the gux-list file.

onMouseup(): void {
this.focusParentList();
}

@Listen('mouseover')
onMouseover(): void {
this.focusParentList();
}

private focusParentList(): void {
const parentList = getClosestElement('gux-list', this.root) as HTMLElement;

if (parentList && parentList.shadowRoot.activeElement === null) {
this.root.blur();
parentList.focus({
preventScroll: true
});
}
}

render(): JSX.Element {
return (
<Host role="listitem">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const validFocusableItems = ['gux-list-item'];
@Component({
styleUrl: 'gux-list.scss',
tag: 'gux-list',
shadow: { delegatesFocus: true }
shadow: true
})
export class GuxList {
@Element()
Expand Down Expand Up @@ -84,14 +84,9 @@ export class GuxList {
last(this.root, validFocusableItems);
}

private renderFocusTarget(): JSX.Element {
return (<span tabindex="-1" aria-hidden="true"></span>) as JSX.Element;
}

render(): JSX.Element {
return (
<Host role="list">
{this.renderFocusTarget()}
Copy link
Collaborator Author

@katie-bobbe-genesys katie-bobbe-genesys Feb 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an issue with having this focus target element. Both of the following cause accessibility issues

  1. Having a focusable element with a role of aria-hidden is a violation
  2. If you remove the aria-hidden, having an element with an invalid role as a descendent of the list is a violation.

I have removed this focus target span and instead put a tab index of -1 on the Host.

<Host tabindex="-1" role="list">
<slot></slot>
</Host>
) as JSX.Element;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`gux-list #render should render component as expected 1`] = `"<gux-list role="list" hydrated=""><template shadowrootmode="open"><span tabindex="-1" aria-hidden="true"></span><slot></slot></template> <gux-list-item role="listitem" hydrated="">Test1</gux-list-item> <gux-list-divider role="presentation" hydrated=""></gux-list-divider> <gux-list-item role="listitem" hydrated="">Test2</gux-list-item> <gux-list-item role="listitem" hydrated="">Test3</gux-list-item> <gux-list-item role="listitem" hydrated="">Test4</gux-list-item> </gux-list>"`;
exports[`gux-list #render should render component as expected 1`] = `"<gux-list tabindex="-1" role="list" hydrated=""><template shadowrootmode="open"><slot></slot></template> <gux-list-item role="listitem" hydrated="">Test1</gux-list-item> <gux-list-divider role="presentation" hydrated=""></gux-list-divider> <gux-list-item role="listitem" hydrated="">Test2</gux-list-item> <gux-list-item role="listitem" hydrated="">Test3</gux-list-item> <gux-list-item role="listitem" hydrated="">Test4</gux-list-item> </gux-list>"`;
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`gux-list #render should render component as expected 1`] = `
<gux-list id="list" role="list">
<gux-list id="list" role="list" tabindex="-1">
<template shadowrootmode="open">
<span aria-hidden="true" tabindex="-1"></span>
<slot></slot>
</template>
<gux-list-item role="listitem">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`gux-popup should display component as expected (1) 1`] = `"<gux-popup hydrated=""><template shadowrootmode="open"><div class="gux-target-container" aria-disabled="false"><slot name="target"></slot><div class="gux-popup-container" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;
exports[`gux-popup should display component as expected (1) 1`] = `"<gux-popup hydrated=""><template shadowrootmode="open"><div class="gux-target-container" aria-disabled="false"><slot name="target"></slot><div class="gux-popup-container" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" tabindex="-1" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;

exports[`gux-popup should display component as expected (2) 1`] = `"<gux-popup expanded="" hydrated=""><template shadowrootmode="open"><div class="gux-target-container" aria-disabled="false"><slot name="target"></slot><div class="gux-popup-container gux-expanded" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;
exports[`gux-popup should display component as expected (2) 1`] = `"<gux-popup expanded="" hydrated=""><template shadowrootmode="open"><div class="gux-target-container" aria-disabled="false"><slot name="target"></slot><div class="gux-popup-container gux-expanded" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" tabindex="-1" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;

exports[`gux-popup should display component as expected (3) 1`] = `"<gux-popup disabled="" hydrated=""><template shadowrootmode="open"><div class="gux-target-container gux-disabled" aria-disabled="true"><slot name="target"></slot><div class="gux-popup-container" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;
exports[`gux-popup should display component as expected (3) 1`] = `"<gux-popup disabled="" hydrated=""><template shadowrootmode="open"><div class="gux-target-container gux-disabled" aria-disabled="true"><slot name="target"></slot><div class="gux-popup-container" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" tabindex="-1" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;

exports[`gux-popup should display component as expected (4) 1`] = `"<gux-popup expanded="" disabled="" hydrated=""><template shadowrootmode="open"><div class="gux-target-container gux-disabled" aria-disabled="true"><slot name="target"></slot><div class="gux-popup-container" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;
exports[`gux-popup should display component as expected (4) 1`] = `"<gux-popup expanded="" disabled="" hydrated=""><template shadowrootmode="open"><div class="gux-target-container gux-disabled" aria-disabled="true"><slot name="target"></slot><div class="gux-popup-container" style="width: 784px; overflow: hidden; left: 8px; top: 42px;"><slot name="popup"></slot></div></div></template> <gux-button slot="target" hydrated="">Target</gux-button> <gux-list slot="popup" tabindex="-1" role="list" hydrated=""> <gux-list-item role="listitem" hydrated="">Item 1</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 2</gux-list-item> <gux-list-item role="listitem" hydrated="">Item 3</gux-list-item> </gux-list> </gux-popup>"`;
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ exports[`gux-table #render empty table 1`] = `"<gux-table gs-table-id="gux-table

exports[`gux-table #render empty table with i18n strings 1`] = `"<gux-table gs-table-id="gux-table-i" hydrated=""><template shadowrootmode="open"><div class="gux-table"><div tabindex="-1" id="gux-table-i" class="gux-table-container"><slot name="data"></slot></div><div class="gux-empty-table">利用可能なデータがありません</div></div></template> <table slot="data"> <thead> <tr> <th>First name</th> <th>Last name</th> <th data-cell-numeric>Age</th> <th data-cell-action>Action</th> </tr> </thead> </table> </gux-table>"`;

exports[`gux-table #render should render a gux-table-select menu 1`] = `"<gux-table gs-table-id="gux-table-i" hydrated=""><template shadowrootmode="open"><div class="gux-table"><div tabindex="-1" id="gux-table-i" class="gux-table-container"><slot name="data"></slot></div></div></template> <table slot="data"> <thead> <tr data-row-id="head"> <th> <gux-table-select-menu hydrated=""><!----> <gux-all-row-select hydrated=""></gux-all-row-select> <button id="gux-table-select-menu-i" aria-haspopup="listbox" aria-expanded="false" type="button" class="gux-select-menu-button"><gux-icon icon-name="custom/chevron-down-small-regular" screenreader-text="Table Options" size="small" hydrated=""></gux-icon></button><gux-popover-list hydrated=""><div><gux-list slot="select-menu-options" role="list" hydrated=""> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> All on page </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> None </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> Bring selected to top </gux-list-item> </gux-list></div></gux-popover-list></gux-table-select-menu> </th> <th data-column-name="first-name">First name</th> <th data-column-name="last-name">Last name</th> <th data-column-name="age" data-cell-numeric>Age</th> <th data-column-name="action" data-cell-action>Action</th> </tr> </thead> <tbody> <tr data-row-id="person-id-1"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>John</td> <td>Doe</td> <td data-cell-numeric>25</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-2"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-3"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>21</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-4"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> </tbody> </table> </gux-table>"`;
exports[`gux-table #render should render a gux-table-select menu 1`] = `"<gux-table gs-table-id="gux-table-i" hydrated=""><template shadowrootmode="open"><div class="gux-table"><div tabindex="-1" id="gux-table-i" class="gux-table-container"><slot name="data"></slot></div></div></template> <table slot="data"> <thead> <tr data-row-id="head"> <th> <gux-table-select-menu hydrated=""><!----> <gux-all-row-select hydrated=""></gux-all-row-select> <button id="gux-table-select-menu-i" aria-haspopup="listbox" aria-expanded="false" type="button" class="gux-select-menu-button"><gux-icon icon-name="custom/chevron-down-small-regular" screenreader-text="Table Options" size="small" hydrated=""></gux-icon></button><gux-popover-list hydrated=""><div><gux-list slot="select-menu-options" tabindex="-1" role="list" hydrated=""> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> All on page </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> None </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> Bring selected to top </gux-list-item> </gux-list></div></gux-popover-list></gux-table-select-menu> </th> <th data-column-name="first-name">First name</th> <th data-column-name="last-name">Last name</th> <th data-column-name="age" data-cell-numeric>Age</th> <th data-column-name="action" data-cell-action>Action</th> </tr> </thead> <tbody> <tr data-row-id="person-id-1"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>John</td> <td>Doe</td> <td data-cell-numeric>25</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-2"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-3"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>21</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-4"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> </tbody> </table> </gux-table>"`;

exports[`gux-table #render should render a gux-table-select menu with i18n strings 1`] = `"<gux-table gs-table-id="gux-table-i" hydrated=""><template shadowrootmode="open"><div class="gux-table"><div tabindex="-1" id="gux-table-i" class="gux-table-container"><slot name="data"></slot></div></div></template> <table slot="data"> <thead> <tr data-row-id="head"> <th> <gux-table-select-menu hydrated=""><!----> <gux-all-row-select hydrated=""></gux-all-row-select> <button id="gux-table-select-menu-i" aria-haspopup="listbox" aria-expanded="false" type="button" class="gux-select-menu-button"><gux-icon icon-name="custom/chevron-down-small-regular" screenreader-text="テーブル オプション" size="small" hydrated=""></gux-icon></button><gux-popover-list hydrated=""><div><gux-list slot="select-menu-options" role="list" hydrated=""> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> All on page </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> None </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> Bring selected to top </gux-list-item> </gux-list></div></gux-popover-list></gux-table-select-menu> </th> <th data-column-name="first-name">First name</th> <th data-column-name="last-name">Last name</th> <th data-column-name="age" data-cell-numeric>Age</th> <th data-column-name="action" data-cell-action>Action</th> </tr> </thead> <tbody> <tr data-row-id="person-id-1"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>John</td> <td>Doe</td> <td data-cell-numeric>25</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-2"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-3"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>21</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-4"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> </tbody> </table> </gux-table>"`;
exports[`gux-table #render should render a gux-table-select menu with i18n strings 1`] = `"<gux-table gs-table-id="gux-table-i" hydrated=""><template shadowrootmode="open"><div class="gux-table"><div tabindex="-1" id="gux-table-i" class="gux-table-container"><slot name="data"></slot></div></div></template> <table slot="data"> <thead> <tr data-row-id="head"> <th> <gux-table-select-menu hydrated=""><!----> <gux-all-row-select hydrated=""></gux-all-row-select> <button id="gux-table-select-menu-i" aria-haspopup="listbox" aria-expanded="false" type="button" class="gux-select-menu-button"><gux-icon icon-name="custom/chevron-down-small-regular" screenreader-text="テーブル オプション" size="small" hydrated=""></gux-icon></button><gux-popover-list hydrated=""><div><gux-list slot="select-menu-options" tabindex="-1" role="list" hydrated=""> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> All on page </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> None </gux-list-item> <gux-list-item onclick="notify(event)" role="listitem" hydrated=""> Bring selected to top </gux-list-item> </gux-list></div></gux-popover-list></gux-table-select-menu> </th> <th data-column-name="first-name">First name</th> <th data-column-name="last-name">Last name</th> <th data-column-name="age" data-cell-numeric>Age</th> <th data-column-name="action" data-cell-action>Action</th> </tr> </thead> <tbody> <tr data-row-id="person-id-1"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>John</td> <td>Doe</td> <td data-cell-numeric>25</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-2"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-3"> <td><gux-row-select disabled="" hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>21</td> <td data-cell-action>Delete</td> </tr> <tr data-row-id="person-id-4"> <td><gux-row-select hydrated=""></gux-row-select></td> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> </tbody> </table> </gux-table>"`;

exports[`gux-table #render should render compact data table 1`] = `"<gux-table compact="" gs-table-id="gux-table-i" gs-compact="" hydrated=""><template shadowrootmode="open"><div class="gux-table"><div tabindex="-1" id="gux-table-i" class="gux-table-container"><slot name="data"></slot></div></div></template> <table slot="data"> <thead> <tr> <th>First name</th> <th>Last name</th> <th data-cell-numeric>Age</th> <th data-cell-action>Action</th> </tr> </thead> <tbody> <tr> <td>John</td> <td>Doe</td> <td data-cell-numeric>25</td> <td data-cell-action>Delete</td> </tr> <tr> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> <tr> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>21</td> <td data-cell-action>Delete</td> </tr> <tr> <td>Jane</td> <td>Doe</td> <td data-cell-numeric>23</td> <td data-cell-action>Delete</td> </tr> </tbody> </table> </gux-table>"`;

Expand Down