Skip to content

Commit bf8caaf

Browse files
authored
fix(ui5-popup): correct focus when there is no focusable content (#2583)
1 parent 59497ee commit bf8caaf

File tree

7 files changed

+61
-25
lines changed

7 files changed

+61
-25
lines changed

packages/main/src/Dialog.js

-11
Original file line numberDiff line numberDiff line change
@@ -203,17 +203,6 @@ class Dialog extends Popup {
203203
return "flex";
204204
}
205205

206-
get classes() {
207-
return {
208-
root: {
209-
"ui5-popup-root": true,
210-
},
211-
content: {
212-
"ui5-popup-content": true,
213-
},
214-
};
215-
}
216-
217206
show() {
218207
super.show();
219208
this._center();

packages/main/src/Popover.js

-11
Original file line numberDiff line numberDiff line change
@@ -655,17 +655,6 @@ class Popover extends Popup {
655655
};
656656
}
657657

658-
get classes() {
659-
return {
660-
root: {
661-
"ui5-popup-root": true,
662-
},
663-
content: {
664-
"ui5-popup-content": true,
665-
},
666-
};
667-
}
668-
669658
/**
670659
* Hook for descendants to hide header.
671660
*/

packages/main/src/Popup.hbs

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
aria-label="{{_ariaLabel}}"
77
aria-labelledby="{{_ariaLabelledBy}}"
88
dir="{{dir}}"
9+
tabindex="-1"
10+
@keydown={{_onkeydown}}
911
>
1012

1113
<span class="first-fe" data-ui5-focus-trap tabindex="0" @focusin={{forwardToLast}}></span>

packages/main/src/Popup.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { getRTL } from "@ui5/webcomponents-base/dist/config/RTL.js";
33
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
44
import { getFirstFocusableElement, getLastFocusableElement } from "@ui5/webcomponents-base/dist/util/FocusableElements.js";
55
import createStyleInHead from "@ui5/webcomponents-base/dist/util/createStyleInHead.js";
6+
import { isTabPrevious } from "@ui5/webcomponents-base/dist/Keys.js";
67
import PopupTemplate from "./generated/templates/PopupTemplate.lit.js";
78
import PopupBlockLayer from "./generated/templates/PopupBlockLayerTemplate.lit.js";
89
import { getNextZIndex, getFocusedElement, isFocusedElementWithinNode } from "./popup-utils/PopupUtils.js";
@@ -242,6 +243,12 @@ class Popup extends UI5Element {
242243
});
243244
}
244245

246+
_onkeydown(e) {
247+
if (e.target === this._root && isTabPrevious(e)) {
248+
e.preventDefault();
249+
}
250+
}
251+
245252
/**
246253
* Focus trapping
247254
* @private
@@ -251,6 +258,8 @@ class Popup extends UI5Element {
251258

252259
if (firstFocusable) {
253260
firstFocusable.focus();
261+
} else {
262+
this._root.focus();
254263
}
255264
}
256265

@@ -263,6 +272,8 @@ class Popup extends UI5Element {
263272

264273
if (lastFocusable) {
265274
lastFocusable.focus();
275+
} else {
276+
this._root.focus();
266277
}
267278
}
268279

@@ -284,7 +295,8 @@ class Popup extends UI5Element {
284295

285296
const element = this.getRootNode().getElementById(this.initialFocus)
286297
|| document.getElementById(this.initialFocus)
287-
|| await getFirstFocusableElement(this);
298+
|| await getFirstFocusableElement(this)
299+
|| this._root; // in case of no focusable content focus the root
288300

289301
if (element) {
290302
element.focus();
@@ -468,6 +480,10 @@ class Popup extends UI5Element {
468480
return this.ariaLabel || undefined;
469481
}
470482

483+
get _root() {
484+
return this.shadowRoot.querySelector(".ui5-popup-root");
485+
}
486+
471487
get dir() {
472488
return getRTL() ? "rtl" : "ltr";
473489
}
@@ -484,8 +500,12 @@ class Popup extends UI5Element {
484500

485501
get classes() {
486502
return {
487-
root: {},
488-
content: {},
503+
root: {
504+
"ui5-popup-root": true,
505+
},
506+
content: {
507+
"ui5-popup-content": true,
508+
},
489509
};
490510
}
491511
}

packages/main/src/themes/PopupsCommon.css

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
overflow: hidden;
2121
max-height: 94vh;
2222
max-width: 90vw;
23+
outline: none;
2324
}
2425

2526
@media screen and (-ms-high-contrast: active) {

packages/main/test/pages/Popover.html

+16
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@
371371
<br>
372372
<br>
373373

374+
<ui5-button id="firstBtn">First button</ui5-button>
375+
<ui5-button id="secondBtn">Second button</ui5-button>
376+
<ui5-popover id="popNoFocusableContent" placement-type="Bottom">Sample text for the ui5-popover</ui5-popover>
377+
378+
<br>
379+
374380
<script>
375381
btn.addEventListener("click", function (event) {
376382
pop.openBy(btn);
@@ -451,6 +457,16 @@
451457
btnOpenXRight.addEventListener("click", function (event) {
452458
popXRight.openBy(targetOpener2);
453459
});
460+
461+
firstBtn.addEventListener("click", (event) => {
462+
popNoFocusableContent.innerHTML = "First button is clicked";
463+
popNoFocusableContent.openBy(event.target);
464+
});
465+
466+
secondBtn.addEventListener("click", (event) => {
467+
popNoFocusableContent.innerHTML = "Second button is clicked";
468+
popNoFocusableContent.openBy(event.target);
469+
});
454470
</script>
455471
</body>
456472

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

+19
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,25 @@ describe("Popover general interaction", () => {
231231

232232
assert.ok(ff.getProperty("focused"), "The first focusable element is focused.");
233233
});
234+
235+
it("tests focus when there is no focusable content", () => {
236+
browser.url("http://localhost:8080/test-resources/pages/Popover.html");
237+
238+
const firstBtn = $("#firstBtn");
239+
const popoverId = "popNoFocusableContent";
240+
241+
firstBtn.click();
242+
243+
let activeElementId = $(browser.getActiveElement()).getAttribute("id");
244+
245+
assert.strictEqual(activeElementId, popoverId, "Popover is focused");
246+
247+
browser.keys(["Shift", "Tab"]);
248+
249+
activeElementId = $(browser.getActiveElement()).getAttribute("id");
250+
251+
assert.ok(activeElementId, popoverId, "Popover remains focused");
252+
});
234253
});
235254

236255
describe("Acc", () => {

0 commit comments

Comments
 (0)