Skip to content

Commit e25a2a7

Browse files
fix(): bug fixes for a better keyboard navigation
1 parent 572221d commit e25a2a7

File tree

3 files changed

+67
-22
lines changed

3 files changed

+67
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [1.1.2] - April 25, 2021
2+
3+
Bug fixes
4+
15
## [1.1.1] - April 23, 2021
26

37
Bug fixes

src/JSPanel.js

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,35 @@ class JSPanel {
7676
}
7777
}
7878
});
79-
this.button.addEventListener("click", (e) => this._togglePanel(e));
80-
this.button.addEventListener("keydown", (e) => this._toggleOnKeyboardEvent(e));
79+
this.button.onclick = (e) => { this._togglePanel(e); };
80+
this.button.onkeydown = (e) => { this._toggleOnKeyboardEvent(e); };
8181
this._insertAfterButton(this.panel);
82+
this.panel.onkeydown = (e) => {
83+
if (e.key === "Tab" || e.keyCode === 9) {
84+
if (this._isOpen())
85+
this._focusInPanel(e);
86+
}
87+
};
88+
// I absolutly want the focus to stay inside (and only INSIDE) the panel :)
89+
// For that, I need to add a keydown event to the button too because
90+
// I want to include it during the keyboard navigation (with Tab)
91+
// So that it's easier for the user to close the panel with his/her keyboard.
92+
this.button.onkeydown = (e) => {
93+
if (e.key === "Tab" || e.keyCode === 9) {
94+
if (this._isOpen()) {
95+
e.preventDefault();
96+
const active_elements = this._getAllActiveItems();
97+
if (active_elements && active_elements[0]) {
98+
if (e.shiftKey === true) {
99+
active_elements[active_elements.length - 2].focus(); // -2 because we don't want to take into account the button once again
100+
}
101+
else {
102+
active_elements[0].focus();
103+
}
104+
}
105+
}
106+
}
107+
};
82108
}
83109
/**
84110
* Following the digital accessibility recommendations for this kind of panels,
@@ -140,7 +166,7 @@ class JSPanel {
140166
}
141167
/**
142168
* Gets all the active items from the panel if it's open.
143-
* @returns {Array<Element>|null} All the items that have an onclick property.
169+
* @returns {Array<HTMLElement>|null} All the items that have an onclick property.
144170
*/
145171
_getAllActiveItems() {
146172
if (this._isOpen()) {
@@ -213,7 +239,6 @@ class JSPanel {
213239
else {
214240
const button = this._createEl("button");
215241
button.setAttribute("aria-label", item.title);
216-
button.setAttribute("tabindex", "0");
217242
if ((item.icon && !item.fontawesome_icon) || (item.icon && item.fontawesome_icon)) {
218243
const icon = this._createEl("img", { attributes: [["src", item.icon]] });
219244
button.appendChild(icon);
@@ -244,12 +269,6 @@ class JSPanel {
244269
item.onclick();
245270
this._closePanel();
246271
});
247-
button.addEventListener("keydown", (e) => {
248-
if (e.key === "Tab" || e.keyCode === 9) {
249-
if (this._isOpen())
250-
this._focusInPanel(e);
251-
}
252-
});
253272
return button;
254273
}
255274
}

src/JSPanel.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,38 @@ class JSPanel {
124124
}
125125
}
126126
});
127-
this.button.addEventListener("click", (e) => this._togglePanel(e));
128-
this.button.addEventListener("keydown", (e) => this._toggleOnKeyboardEvent(e));
127+
128+
this.button.onclick = (e) => { this._togglePanel(e) };
129+
this.button.onkeydown = (e) => { this._toggleOnKeyboardEvent(e) };
129130

130131
this._insertAfterButton(this.panel);
132+
133+
this.panel.onkeydown = (e: KeyboardEvent) => {
134+
if (e.key === "Tab" || e.keyCode === 9) {
135+
if (this._isOpen()) this._focusInPanel(e);
136+
}
137+
};
138+
139+
// I absolutly want the focus to stay inside (and only INSIDE) the panel :)
140+
// For that, I need to add a keydown event to the button too because
141+
// I want to include it during the keyboard navigation (with Tab)
142+
// So that it's easier for the user to close the panel with his/her keyboard.
143+
this.button.onkeydown = (e: KeyboardEvent) => {
144+
if (e.key === "Tab" || e.keyCode === 9) {
145+
if (this._isOpen()) {
146+
e.preventDefault();
147+
148+
const active_elements = this._getAllActiveItems();
149+
if (active_elements && active_elements[0]) {
150+
if (e.shiftKey === true) {
151+
active_elements[active_elements.length - 2].focus(); // -2 because we don't want to take into account the button once again
152+
} else {
153+
active_elements[0].focus();
154+
}
155+
}
156+
}
157+
}
158+
};
131159
}
132160

133161
/**
@@ -192,9 +220,9 @@ class JSPanel {
192220

193221
/**
194222
* Gets all the active items from the panel if it's open.
195-
* @returns {Array<Element>|null} All the items that have an onclick property.
223+
* @returns {Array<HTMLElement>|null} All the items that have an onclick property.
196224
*/
197-
private _getAllActiveItems(): Element[] | null {
225+
private _getAllActiveItems(): HTMLElement[] | null {
198226
if (this._isOpen()) {
199227
const active_elements: HTMLElement[] = Array.from((this.panel as HTMLElement).querySelectorAll("button"));
200228
active_elements.push(this.button as HTMLElement);
@@ -300,12 +328,6 @@ class JSPanel {
300328
this._closePanel();
301329
});
302330

303-
window.addEventListener("keydown", (e: KeyboardEvent) => {
304-
if (e.key === "Tab" || e.keyCode === 9) {
305-
if (this._isOpen()) this._focusInPanel(e);
306-
}
307-
});
308-
309331
return button;
310332
}
311333
}
@@ -330,7 +352,7 @@ class JSPanel {
330352
if(index < 0) {
331353
index = all_items.length - 1;
332354
}
333-
(all_items[index] as HTMLElement).focus();
355+
all_items[index].focus();
334356
}
335357
}
336358

@@ -376,4 +398,4 @@ class JSPanel {
376398
max = Math.floor(max);
377399
return Math.floor(Math.random() * (max - min)) + min;
378400
}
379-
}
401+
}

0 commit comments

Comments
 (0)