Skip to content

Commit bda9407

Browse files
committed
fix: Trap focus inside modal. Fixes kylefox#268
1 parent a8b9c9b commit bda9407

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
@@ -85,6 +85,9 @@
8585
open: function() {
8686
var m = this;
8787
this.block();
88+
// Store previous focus
89+
this.previousFocus = document.activeElement;
90+
8891
this.anchor.blur();
8992
if(this.options.doFade) {
9093
setTimeout(function() {
@@ -148,6 +151,7 @@
148151
} else {
149152
this.$elm.css('display', 'inline-block');
150153
}
154+
this.trapFocus();
151155
this.$elm.trigger($.modal.OPEN, [this._ctx()]);
152156
},
153157

@@ -164,6 +168,7 @@
164168
_this.$elm.trigger($.modal.AFTER_CLOSE, [_this._ctx()]);
165169
});
166170
}
171+
this.releaseFocus();
167172
this.$elm.trigger($.modal.CLOSE, [this._ctx()]);
168173
},
169174

@@ -179,6 +184,46 @@
179184
if (this.spinner) this.spinner.remove();
180185
},
181186

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

0 commit comments

Comments
 (0)