Skip to content

Commit cfa50d8

Browse files
authoredApr 1, 2021
fix(ui5-busyindicator): add a11y support (#2938)
Tooltip, Focus is provided, so screen readers can read the component properly Fixes #2381
1 parent f4301b8 commit cfa50d8

File tree

5 files changed

+84
-41
lines changed

5 files changed

+84
-41
lines changed
 

‎packages/main/src/BusyIndicator.hbs

+21-12
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
<div class="{{classes.root}}">
2-
<div class="ui5-busyindicator-wrapper">
3-
{{#if active}}
4-
<div class="ui5-busyindicator-dynamic-content" role="progressbar" aria-valuemin="0" aria-valuemax="100" title="{{ariaTitle}}">
2+
{{#if active}}
3+
<div
4+
class="ui5-busyindicator-busy-area"
5+
title="{{ariaTitle}}"
6+
tabindex="0"
7+
role="progressbar"
8+
aria-valuemin="0"
9+
aria-valuemax="100"
10+
aria-valuetext="Busy"
11+
aria-labelledby="{{_id}}-label"
12+
>
13+
<div class="ui5-busyindicator-circles-wrapper">
514
<div class="ui5-busyindicator-circle circle-animation-0"></div>
615
<div class="ui5-busyindicator-circle circle-animation-1"></div>
716
<div class="ui5-busyindicator-circle circle-animation-2"></div>
817
</div>
9-
{{/if}}
10-
{{#if text}}
11-
<ui5-label class="ui5-busyindicator-text">
12-
{{text}}
13-
</ui5-label>
14-
{{/if}}
15-
</div>
18+
{{#if text}}
19+
<ui5-label id="{{_id}}-label" class="ui5-busyindicator-text">
20+
{{text}}
21+
</ui5-label>
22+
{{/if}}
23+
</div>
24+
{{/if}}
1625

17-
<slot></slot>
18-
</div>
26+
<slot tabindex="{{slotTabIndex}}"></slot>
27+
</div>

‎packages/main/src/BusyIndicator.js

+4-8
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,6 @@ class BusyIndicator extends UI5Element {
110110
this._preventHandler = this._preventEvent.bind(this);
111111
}
112112

113-
onBeforeRendering() {
114-
if (this.active) {
115-
this.tabIndex = -1;
116-
} else {
117-
this.removeAttribute("tabindex");
118-
}
119-
}
120-
121113
onEnterDOM() {
122114
this.addEventListener("keyup", this._preventHandler, {
123115
capture: true,
@@ -170,6 +162,10 @@ class BusyIndicator extends UI5Element {
170162
};
171163
}
172164

165+
get slotTabIndex() {
166+
return this.active ? -1 : 0;
167+
}
168+
173169
_preventEvent(event) {
174170
if (this.active) {
175171
event.stopImmediatePropagation();

‎packages/main/src/themes/BusyIndicator.css

+17-18
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@
22
display: inline-block;
33
}
44

5-
:host(:not([active])) .ui5-busyindicator-wrapper {
6-
display: none;
7-
}
8-
95
:host([active]) {
106
color: var(--sapContent_IconColor);
11-
pointer-events: none;
127
}
138

149
:host([active]) :not(.ui5-busyindicator-root--ie) ::slotted(:not([class^="ui5-busyindicator-"])) {
@@ -75,15 +70,27 @@
7570
background-color: inherit;
7671
}
7772

78-
.ui5-busyindicator-wrapper {
73+
.ui5-busyindicator-busy-area {
7974
position: absolute;
8075
z-index: 99;
81-
width: 100%;
82-
/* Fixes IE positioning */
8376
left: 0;
8477
right: 0;
85-
top: 50%;
86-
transform: translate(0, -50%);
78+
top: 0;
79+
bottom: 0;
80+
display: flex;
81+
justify-content: center;
82+
align-items: center;
83+
background-color: inherit;
84+
flex-direction: column;
85+
}
86+
87+
.ui5-busyindicator-busy-area:focus {
88+
outline: 1px dotted var(--sapContent_FocusColor);
89+
outline-offset: -2px;
90+
}
91+
92+
.ui5-busyindicator-circles-wrapper {
93+
line-height: 0;
8794
}
8895

8996
.ui5-busyindicator-circle {
@@ -99,14 +106,6 @@
99106
border-radius: 100%;
100107
}
101108

102-
.ui5-busyindicator-dynamic-content {
103-
height: 100%;
104-
display: flex;
105-
justify-content: center;
106-
align-items: center;
107-
background-color: inherit;
108-
}
109-
110109
.circle-animation-0 {
111110
animation: grow 1.6s infinite cubic-bezier(0.32, 0.06, 0.85, 1.11);
112111
}

‎packages/main/test/pages/BusyIndicator.html

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
<head>
55
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
77
<meta charset="utf-8">
88

99
<title>Busy Indicator</title>
@@ -40,12 +40,12 @@
4040

4141
<br />
4242
<br />
43-
<ui5-busyindicator active id="indicator2" text="Loading" style="width: 10rem; border: 1px solid red"></ui5-busyindicator>
43+
<ui5-busyindicator active text="Loading" style="width: 10rem; border: 1px solid red"></ui5-busyindicator>
4444

4545
<br />
4646
<br />
4747

48-
<ui5-busyindicator size="Medium" active>
48+
<ui5-busyindicator id="indicatorWithBtn" size="Medium" active>
4949
<ui5-button>Hello World</ui5-button>
5050
</ui5-busyindicator>
5151

@@ -79,6 +79,14 @@
7979
</ui5-list>
8080
</ui5-busyindicator>
8181

82+
<ui5-busyindicator size="Medium" active style="width: 500px; margin-left: 100px" text="Custom loading text">
83+
<ui5-list style="width: 100%; border: 1px solid black;">
84+
<ui5-li>Item 1</ui5-li>
85+
<ui5-li>Item 2</ui5-li>
86+
<ui5-li>Item 3</ui5-li>
87+
</ui5-list>
88+
</ui5-busyindicator>
89+
8290
<br>
8391
<br>
8492
<br>

‎packages/main/test/specs/BusyIndicator.spec.js

+31
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,35 @@ describe("BusyIndicator general interaction", () => {
1818
assert.strictEqual(input.getProperty("value"), "0", "itemClick is not thrown");
1919
});
2020

21+
it("tests focus handling", () => {
22+
const busyIndicator = browser.$("#indicator1");
23+
busyIndicator.click();
24+
25+
let innerFocusElement = browser.execute(() => {
26+
return document.getElementById("indicator1").shadowRoot.activeElement;
27+
});
28+
29+
innerFocusElement = $(innerFocusElement);
30+
31+
assert.strictEqual(innerFocusElement.getAttribute("class"), "ui5-busyindicator-busy-area", "The correct inner element is focused");
32+
});
33+
34+
it("tests internal focused element attributes", () => {
35+
const busyIndicator = browser.$("#indicator1");
36+
busyIndicator.click();
37+
const innerFocusElement = busyIndicator.shadow$(".ui5-busyindicator-busy-area");
38+
39+
assert.strictEqual(innerFocusElement.getAttribute("role"), "progressbar", "Correct 'role' is set");
40+
assert.strictEqual(innerFocusElement.getAttribute("tabindex"), "0", "Correct 'tabindex' is set");
41+
assert.strictEqual(innerFocusElement.getAttribute("aria-valuemin"), "0", "Correct 'aria-valuemin' is set");
42+
assert.strictEqual(innerFocusElement.getAttribute("aria-valuemax"), "100", "Correct 'aria-valuemax' is set");
43+
assert.strictEqual(innerFocusElement.getAttribute("aria-valuetext"), "Busy", "Correct 'aria-valuetext' is set");
44+
});
45+
46+
it("tests content is not reachable with keyboard when active", () => {
47+
const busyIndicator = browser.$("#indicatorWithBtn");
48+
const defaultSLot = busyIndicator.shadow$("slot");
49+
50+
assert.strictEqual(defaultSLot.getAttribute("tabindex"), "-1", "Slot is not reachable via keyboard");
51+
});
2152
});

0 commit comments

Comments
 (0)
Please sign in to comment.