Skip to content

Commit 9e6998f

Browse files
nnaydenowvladitasev
authored andcommitted
feat(ui5-panel): support aria-label and aria-labelledby (#1910)
1 parent f5a6735 commit 9e6998f

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

packages/main/src/Panel.hbs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
role="{{accInfo.role}}"
1414
aria-expanded="{{accInfo.ariaExpanded}}"
1515
aria-controls="{{accInfo.ariaControls}}"
16+
aria-label="{{accInfo.ariaLabel}}"
17+
aria-labelledby="{{accInfo.ariaLabelledby}}"
1618
>
1719
{{#unless fixed}}
1820
<div class="ui5-panel-header-button-root">
@@ -23,6 +25,8 @@
2325
?non-focusable="{{nonFocusableButton}}"
2426
@click="{{_toggleButtonClick}}"
2527
._buttonAccInfo="{{accInfo.button}}"
28+
aria-label="{{accInfo.ariaLabelButton}}"
29+
aria-labelledby="{{accInfo.ariaLabelledbyButton}}"
2630
></ui5-button>
2731
</div>
2832
{{/unless}}
@@ -31,6 +35,7 @@
3135
<slot name="header"></slot>
3236
{{else}}
3337
<div
38+
id="{{_id}}-header-title"
3439
role="heading"
3540
aria-level="{{headerAriaLevel}}"
3641
class="ui5-panel-header-title"

packages/main/src/Panel.js

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import slideDown from "@ui5/webcomponents-base/dist/animations/slideDown.js";
44
import slideUp from "@ui5/webcomponents-base/dist/animations/slideUp.js";
55
import { isSpace, isEnter } from "@ui5/webcomponents-base/dist/Keys.js";
66
import AnimationMode from "@ui5/webcomponents-base/dist/types/AnimationMode.js";
7+
import getEffectiveAriaLabelText from "@ui5/webcomponents-base/dist/util/getEffectiveAriaLabelText.js";
78
import { getAnimationMode } from "@ui5/webcomponents-base/dist/config/AnimationMode.js";
89
import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js";
910
import "@ui5/webcomponents-icons/dist/icons/navigation-right-arrow.js";
@@ -116,7 +117,27 @@ const metadata = {
116117
type: TitleLevel,
117118
defaultValue: TitleLevel.H2,
118119
},
119-
120+
/**
121+
* @type {String}
122+
* @defaultvalue ""
123+
* @private
124+
* @since 1.0.0-rc.8
125+
*/
126+
ariaLabel: {
127+
type: String,
128+
},
129+
/**
130+
* Receives id(or many ids) of the elements that label the panel
131+
*
132+
* @type {String}
133+
* @defaultvalue ""
134+
* @private
135+
* @since 1.0.0-rc.8
136+
*/
137+
ariaLabelledby: {
138+
type: String,
139+
defaultValue: "",
140+
},
120141
/**
121142
* @private
122143
*/
@@ -341,10 +362,6 @@ class Panel extends UI5Element {
341362
return !this.collapsed;
342363
}
343364

344-
get ariaLabelledBy() {
345-
return this.header.length ? "" : `${this._id}-header`;
346-
}
347-
348365
get accRole() {
349366
return this.accessibleRole.toLowerCase();
350367
}
@@ -356,12 +373,28 @@ class Panel extends UI5Element {
356373
"ariaControls": this._hasHeader ? `${this._id}-content` : undefined,
357374
"title": this.toggleButtonTitle,
358375
},
359-
"ariaExpanded": !this._hasHeader ? this.expanded : undefined,
360-
"ariaControls": !this._hasHeader ? `${this._id}-content` : undefined,
361-
"role": !this._hasHeader ? "button" : undefined,
376+
"ariaExpanded": this.nonFixedInternalHeader ? this.expanded : undefined,
377+
"ariaControls": this.nonFixedInternalHeader ? `${this._id}-content` : undefined,
378+
"ariaLabelledby": this.nonFocusableButton ? this.ariaLabelledbyReference : undefined,
379+
"ariaLabel": this.nonFocusableButton ? this.ariaLabelTxt : undefined,
380+
"ariaLabelledbyButton": this.nonFocusableButton ? undefined : this.ariaLabelledbyReference,
381+
"ariaLabelButton": this.nonFocusableButton ? undefined : this.ariaLabelTxt,
382+
"role": this.nonFixedInternalHeader ? "button" : undefined,
362383
};
363384
}
364385

386+
get ariaLabelledbyReference() {
387+
if (this.ariaLabelledby || this.ariaLabel) {
388+
return undefined;
389+
}
390+
391+
return (this.nonFocusableButton && this.headerText) ? `${this._id}-header-title` : undefined;
392+
}
393+
394+
get ariaLabelTxt() {
395+
return getEffectiveAriaLabelText(this);
396+
}
397+
365398
get headerAriaLevel() {
366399
return this.headerLevel.slice(1);
367400
}
@@ -370,6 +403,10 @@ class Panel extends UI5Element {
370403
return (this.header.length || this.fixed) ? "-1" : "0";
371404
}
372405

406+
get nonFixedInternalHeader() {
407+
return !this._hasHeader && !this.fixed;
408+
}
409+
373410
get nonFocusableButton() {
374411
return !this.header.length;
375412
}

packages/main/test/pages/Panel.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@
6161
}
6262
</style>
6363

64-
<ui5-panel id="p1" collapsed accessible-role="Complementary">
64+
<ui5-panel id="p1" collapsed accessible-role="Complementary" aria-labelledby="p1-title">
6565

6666
<!-- Panel header -->
6767
<div slot="header" class="header">
68-
<ui5-title>Expandable but not expanded</ui5-title>
68+
<ui5-title id="p1-title">Expandable but not expanded</ui5-title>
6969
<ui5-button id="b1">Add child </ui5-button>
7070
<ui5-label id="l1">No new children added yet.</ui5-label>
7171
<ui5-button design="Reject" icon="cancel">Cancel</ui5-button>

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,31 @@ describe("Panel general interaction", () => {
114114
assert.strictEqual(title.getAttribute("aria-level"), "3", "title aria-level is set to 3 correctly");
115115
});
116116

117+
it("tests aria-label and aria-labelledby attributes", () => {
118+
const panelWithNativeHeader = $("#panel-expandable");
119+
const nativeHeader = panelWithNativeHeader.shadow$(".ui5-panel-header");
120+
const panelWithNativeHeaderId = panelWithNativeHeader.getProperty("_id");
121+
122+
assert.strictEqual(nativeHeader.getAttribute("aria-label"), null, "aria-label is not present");
123+
assert.strictEqual(nativeHeader.getAttribute("aria-labelledby"),
124+
`${panelWithNativeHeaderId}-header-title`, "aria-labelledby is correct");
125+
126+
const panelWithCustomHeader = $("#p1");
127+
const headerButton = panelWithCustomHeader.shadow$(".ui5-panel-header-button");
128+
const expectedText = "Expandable but not expanded";
129+
130+
assert.strictEqual(headerButton.getAttribute("aria-label"), expectedText,
131+
"aria-labelledby is propagated correctly to the expand/collapse button");
132+
});
133+
134+
it("tests whether aria attributes are set correctly with fixed header", () => {
135+
const header = browser.$("#panel-fixed").shadow$(".ui5-panel-header");
136+
137+
assert.ok(!header.getAttribute("aria-expanded"), "aria-expanded shouldn't be set on the fixed header");
138+
assert.ok(!header.getAttribute("aria-controls"), "aria-controls shouldn't be set on the fixed header");
139+
assert.ok(!header.getAttribute("role"), "role shouldn't be set on the fixed header");
140+
});
141+
117142
it("tests whether aria attributes are set correctly in case of custom header", () => {
118143
const button = browser.$("#panel2").shadow$(".ui5-panel-header-button").shadow$(".ui5-button-root");
119144
const header = browser.$("#panel2").shadow$(".ui5-panel-header");

0 commit comments

Comments
 (0)