3

I have a modal window that pops up when you click a .btn link.

When it is active, users can still press Tab to focus on links and buttons in the background, some of which have download links. When these links are focused on and user pressed enter key the download action takeplace.

Is there a way to disable background Tab while the modal window is active?

I am using below versions:

https://valor-software.com/ngx-bootstrap/#/modals (V2.4), Angular CLI 1.6

svs
  • 251
  • 1
  • 4
  • 12
  • I have found a similar issue and answer, converted the "disableTabModalShown" function to directive in my application. https://stackoverflow.com/questions/25142244/disable-tab-key-focusing-while-bootstrap-modal-is-active – svs Apr 24 '18 at 11:55

2 Answers2

4

Since the latest ngx-bootstrap(v2.4) does not have the fix, I created a directive to trap tab key focus in the modal box itself.

Angular Version I used is, Angular 5

My directive is below.

Directive

import {Directive, ElementRef, HostListener} from '@angular/core';
@Directive({
    selector: '[appSdbModalFocus]'
})
export class SdbModalFocusDirective {
    KEYCODE_TAB: number = 9;

    constructor(
        private hostElement: ElementRef
    ) {}

    ngOnInit() {}

    @HostListener("keydown", ["$event"])
    onKeyDown(e: KeyboardEvent): any {
        if (e.key === 'Tab' || e.keyCode === this.KEYCODE_TAB) {
            let focusableEls = this.hostElement.nativeElement;
            let modalContent = $(focusableEls).find('a, :input, [tabindex]');
            var firstFocusableEl = modalContent.first()[0];
            var lastFocusableEl = modalContent.last()[0];

            if (e.shiftKey) /* shift + tab */ {
                this.log(firstFocusableEl, lastFocusableEl, document);
                if (document.activeElement === firstFocusableEl) {
                    lastFocusableEl.focus();
                    e.preventDefault();
                }
            } else /* tab */ {
                this.log(firstFocusableEl, lastFocusableEl, document);
                if (document.activeElement === lastFocusableEl) {
                    firstFocusableEl.focus();
                    e.preventDefault();
                }    
            }
        }
    }
}

HTML

<form appSdbModalFocus>
...
</form>

Created this directive with the help of trap-focus-in-an-element

svs
  • 251
  • 1
  • 4
  • 12
  • Thanks! I've implemented this solution myself. You should accept your own answer. – Chanandler Bong Nov 23 '18 at 14:27
  • It works, until I add button to the modal content (find('a, button, :input, ...). Also, it only seems to work if the directive is applied to a form. I'd like to move it upward, so it covers the entire modal (a close button on top, some buttons on bottom). Any reason the directive should not work if applied to a div that wraps the form and modal-header, modal-footer? – Wallace Howery Feb 21 '19 at 19:19
  • This solution uses $(...).find() and I've seen another similar example that uses .querySelectAll(). However, how could this be replaced using Angular's @ViewChildren? – Sevenfold Aug 25 '20 at 15:22
-1

you should use a class on the background page, which has a pointer-events: none; when the modal is up. Just use ngClass so it could be dynamically changed on click your .btn, and toggled on the modal closing event.

Luca Taccagni
  • 1,059
  • 6
  • 23
  • Is it possible to restrict tab inside modal box itself? – svs Apr 23 '18 at 14:05
  • I think that the pointer-events: none; already does it; Are you asking something like: the mouse pointer can't escape from modal box? – Luca Taccagni Apr 23 '18 at 14:08
  • I want to circulate tab key inside the modal box itself like in the demo https://getbootstrap.com/docs/4.0/components/modal/#live-demo. In the plugin which I am using it is not working now. I am in search of the solution for that. – svs Apr 24 '18 at 04:26
  • as i can see in that example, you could use the pointer events! So i think you're asking how to make modal close when you click outside, don't you? – Luca Taccagni Apr 24 '18 at 07:33