Skip to content

Commit e6dd404

Browse files
authored
Merge pull request #7 from Zenoo/fix-268
fix: Trap focus inside modal. Fixes kylefox#268
2 parents 10d0588 + bda9407 commit e6dd404

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

jquery.modal.js

+45
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@
9191
open: function() {
9292
var m = this;
9393
this.block();
94+
// Store previous focus
95+
this.previousFocus = document.activeElement;
96+
9497
this.anchor.blur();
9598
if(this.options.doFade) {
9699
setTimeout(function() {
@@ -156,6 +159,7 @@
156159
} else {
157160
this.$elm.css('display', 'inline-block');
158161
}
162+
this.trapFocus();
159163
this.$elm.trigger($.modal.OPEN, [this._ctx()]);
160164
},
161165

@@ -172,6 +176,7 @@
172176
_this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]);
173177
});
174178
}
179+
this.releaseFocus();
175180
this.$elm.trigger($.modal.CLOSE, [this._ctx()]);
176181
},
177182

@@ -187,6 +192,46 @@
187192
if (this.spinner) this.spinner.remove();
188193
},
189194

195+
// Trap focus in modal for screen readers & keyboard navigation
196+
trapFocus: function() {
197+
// All focusable elements
198+
var focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
199+
200+
var firstFocusableElement = this.$elm[0].querySelectorAll(focusableElements)[0]; // get first element to be focused inside modal
201+
var focusableContent = this.$elm[0].querySelectorAll(focusableElements);
202+
var lastFocusableElement = focusableContent[focusableContent.length - 1]; // get last element to be focused inside modal
203+
204+
205+
$(this.$elm).on('keydown', function(e) {
206+
let isTabPressed = e.key === 'Tab' || e.keyCode === 9;
207+
208+
if (!isTabPressed) {
209+
return;
210+
}
211+
212+
if (e.shiftKey) { // if shift key pressed for shift + tab combination
213+
if (document.activeElement === firstFocusableElement) {
214+
lastFocusableElement.focus(); // add focus for the last focusable element
215+
e.preventDefault();
216+
}
217+
} else { // if tab key is pressed
218+
if (document.activeElement === lastFocusableElement) { // if focused has reached to last focusable element then focus first focusable element after pressing tab
219+
firstFocusableElement.focus(); // add focus for the first focusable element
220+
e.preventDefault();
221+
}
222+
}
223+
});
224+
225+
firstFocusableElement.focus();
226+
},
227+
228+
releaseFocus: function() {
229+
$(this.$elm).off('keydown');
230+
231+
// Restore previous focus
232+
this.previousFocus.focus();
233+
},
234+
190235
//Return context for custom events
191236
_ctx: function() {
192237
return { elm: this.$elm, $elm: this.$elm, $blocker: this.$blocker, options: this.options, $anchor: this.anchor };

0 commit comments

Comments
 (0)