Skip to content

Commit cacf5d8

Browse files
authored
feat(ui5-list): support aria-label and aria-labelledby (#1899)
Add support for aria-label and aria-labelledby: - if aria-label or aria-labelledby are set externally, aria-label is set inside the shadowDOM. - if not, aria-labelledby is set to reference the internal header, when the header-text property is set. It is now possible to label the list as shown: FIXES: #1886
1 parent fd9a546 commit cacf5d8

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

packages/main/src/List.hbs

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616

1717
<div id="{{_id}}-before" tabindex="0" class="ui5-list-focusarea"></div>
1818

19-
<ul id="{{_id}}-listUl" class="ui5-list-ul" aria-multiselectable="{{isMultiSelect}}" aria-labelledby="{{ariaLabelledBy}}" role="{{_role}}">
19+
<ul id="{{_id}}-listUl"
20+
class="ui5-list-ul"
21+
role="{{_role}}"
22+
aria-label="{{ariaLabelТxt}}"
23+
aria-labelledby="{{ariaLabelledBy}}"
24+
aria-multiselectable="{{isMultiSelect}}"
25+
>
2026
<slot></slot>
2127

2228
{{#if showNoDataText}}

packages/main/src/List.js

+32
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ItemNavigation from "@ui5/webcomponents-base/dist/delegate/ItemNavigation
44
import { getLastTabbableElement } from "@ui5/webcomponents-base/dist/util/TabbableElements.js";
55
import { isTabNext } from "@ui5/webcomponents-base/dist/Keys.js";
66
import NavigationMode from "@ui5/webcomponents-base/dist/types/NavigationMode.js";
7+
import getEffectiveAriaLabelText from "@ui5/webcomponents-base/dist/util/getEffectiveAriaLabelText.js";
78
import ListMode from "./types/ListMode.js";
89
import ListSeparators from "./types/ListSeparators.js";
910
import BusyIndicator from "./BusyIndicator.js";
@@ -163,6 +164,29 @@ const metadata = {
163164
type: Boolean,
164165
},
165166

167+
/**
168+
* @type {String}
169+
* @defaultvalue ""
170+
* @private
171+
* @since 1.0.0-rc.8
172+
*/
173+
ariaLabel: {
174+
type: String,
175+
},
176+
177+
/**
178+
* Receives id(or many ids) of the elements that label the input
179+
*
180+
* @type {String}
181+
* @defaultvalue ""
182+
* @private
183+
* @since 1.0.0-rc.8
184+
*/
185+
ariaLabelledby: {
186+
type: String,
187+
defaultValue: "",
188+
},
189+
166190
/**
167191
* Used to externally manipulate the role of the list
168192
*
@@ -368,9 +392,17 @@ class List extends UI5Element {
368392
}
369393

370394
get ariaLabelledBy() {
395+
if (this.ariaLabelledby || this.ariaLabel) {
396+
return undefined;
397+
}
398+
371399
return this.shouldRenderH1 ? this.headerID : undefined;
372400
}
373401

402+
get ariaLabelТxt() {
403+
return getEffectiveAriaLabelText(this);
404+
}
405+
374406
onBeforeRendering() {
375407
this.prepareListItems();
376408
}

packages/main/test/pages/List_test_page.html

+16
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,22 @@
131131
<ui5-li id="detailListItem" type="Detail">Detail item</ui5-li>
132132
<ui5-li >Normal item</ui5-li>
133133
</ui5-list>
134+
<br/><br/>
135+
136+
<ui5-list id="listWithInternalHeader" header-text="Test aria">
137+
<ui5-li>item</ui5-li>
138+
<ui5-li >item</ui5-li>
139+
</ui5-list>
140+
<br/><br/>
141+
142+
<ui5-list id="listWithCustomHeader" aria-labelledby="testHeader">
143+
<div slot="header" class="header">
144+
<h2 id="testHeader">Test aria</h2>
145+
</div>
146+
147+
<ui5-li>item</ui5-li>
148+
<ui5-li >item</ui5-li>
149+
</ui5-list>
134150

135151
<script>
136152
'use strict';

packages/main/test/specs/List.spec.js

+24-1
Original file line numberDiff line numberDiff line change
@@ -234,10 +234,33 @@ describe("List Tests", () => {
234234
it("detailPress event is fired", () => {
235235
const detailCounterResult = $("#detailPressCounter");
236236
const firstItem = $("#detailListItem");
237-
const detailButton = firstItem.shadow$(".ui5-li-detailbtn")
237+
const detailButton = firstItem.shadow$(".ui5-li-detailbtn");
238238

239239
detailButton.click();
240240

241241
assert.strictEqual(detailCounterResult.getProperty("innerHTML"), "1", "detailClick event has been fired once");
242242
});
243+
244+
it("tests aria-labelledby", () => {
245+
const listWithInternalHeader = $("#listWithInternalHeader");
246+
const listWithCustomHeader = $("#listWithCustomHeader");
247+
const ulInternalHeader = listWithInternalHeader.shadow$(".ui5-list-ul");
248+
const ulCustomHeader = listWithCustomHeader.shadow$(".ui5-list-ul");
249+
250+
// assert: List with internal header
251+
const listWithInternalHeaderId = listWithInternalHeader.getProperty("_id");
252+
assert.strictEqual(ulInternalHeader.getAttribute("aria-label"),
253+
null, "aria-label is not present");
254+
255+
assert.strictEqual(ulInternalHeader.getAttribute("aria-labelledby"),
256+
`${listWithInternalHeaderId}-header`, "aria-labelledby is correct");
257+
258+
// assert: List with custom header
259+
const EXPECTED_ARIA_LABEL_TXT = "Test aria";
260+
261+
assert.strictEqual(ulCustomHeader.getAttribute("aria-label"),
262+
EXPECTED_ARIA_LABEL_TXT, "aria-label is correct");
263+
assert.strictEqual(ulCustomHeader.getAttribute("aria-labelledby"),
264+
null, "aria-labelledby is not present");
265+
});
243266
});

0 commit comments

Comments
 (0)