Skip to content

Commit 70832aa

Browse files
committed
add tab focus
1 parent b7d4a24 commit 70832aa

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

index.html

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
<h1>Lightweight vanilla js modal component</h1>
4141
<p>
4242
This is just 2kb Lightweight vanilla js modal component with zero
43-
dependencies , with option esc close , outside click close , custom
44-
height , widht : check code in github :
43+
dependencies , with option esc close , outside click close , tab key
44+
focus inside Modal custom height , widht : check code in github :
4545
<a href="https://github.com/idurar/vanilla-js-modal">
4646
vanilla js modal github repo</a
4747
>
@@ -53,6 +53,11 @@ <h1>Lightweight vanilla js modal component</h1>
5353
<div id="delete-record" style="display: none">
5454
<div class="popup-container">
5555
<p>your Modal content here !</p>
56+
<input
57+
type="text"
58+
style="float: left; margin-right: 20px; height: 35px"
59+
/>
60+
<button class="closeModal" style="margin: 0">close Modal</button>
5661
</div>
5762
</div>
5863
</body>

src/modal.js

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,54 @@ function closeClick(e) {
1818
closeModal();
1919
}
2020
}
21+
function trapTabKey(e) {
22+
const vanillaModal = document.querySelector(".vanilla-modal");
23+
const FOCUSABLE_ELEMENTS = [
24+
"a[href]",
25+
"area[href]",
26+
'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',
27+
"select:not([disabled]):not([aria-hidden])",
28+
"textarea:not([disabled]):not([aria-hidden])",
29+
"button:not([disabled]):not([aria-hidden])",
30+
"iframe",
31+
"object",
32+
"embed",
33+
"[contenteditable]",
34+
'[tabindex]:not([tabindex^="-"])',
35+
];
36+
37+
const nodes = vanillaModal.querySelectorAll(FOCUSABLE_ELEMENTS);
38+
let focusableNodes = Array(...nodes);
39+
40+
if (focusableNodes.length === 0) return;
41+
42+
focusableNodes = focusableNodes.filter((node) => {
43+
return node.offsetParent !== null;
44+
});
45+
46+
// if disableFocus is true
47+
if (!vanillaModal.contains(document.activeElement)) {
48+
focusableNodes[0].focus();
49+
} else {
50+
const focusedItemIndex = focusableNodes.indexOf(document.activeElement);
51+
52+
if (e.shiftKey && focusedItemIndex === 0) {
53+
focusableNodes[focusableNodes.length - 1].focus();
54+
e.preventDefault();
55+
}
2156

22-
const closeModal = function () {
57+
if (
58+
!e.shiftKey &&
59+
focusableNodes.length > 0 &&
60+
focusedItemIndex === focusableNodes.length - 1
61+
) {
62+
focusableNodes[0].focus();
63+
e.preventDefault();
64+
}
65+
}
66+
}
67+
68+
function closeModal() {
2369
const vanillaModal = document.querySelector(".vanilla-modal");
2470
if (vanillaModal) {
2571
vanillaModal.classList.remove("modal-visible");
@@ -30,7 +76,8 @@ const closeModal = function () {
3076
document.removeEventListener("keydown", escKey);
3177
document.removeEventListener("click", outsideClick, true);
3278
document.removeEventListener("click", closeClick);
33-
};
79+
document.removeEventListener("keydown", trapTabKey);
80+
}
3481

3582
const modal = {
3683
init: function () {
@@ -66,6 +113,7 @@ const modal = {
66113
vanillaModal.classList.add("modal-visible");
67114
document.addEventListener("click", outsideClick, true);
68115
document.addEventListener("keydown", escKey);
116+
document.addEventListener("keydown", trapTabKey);
69117
document
70118
.getElementById("modal-content")
71119
.addEventListener("click", closeClick);

0 commit comments

Comments
 (0)