Multiple modals overlay Multiple modals overlay javascript javascript

Multiple modals overlay


After seeing many fixes for this, and none of them were exactly what I needed I've came up with a even shorter solution that is inspired by @YermoLamers & @Ketwaroo.

Backdrop z-index fix
This solution uses a setTimeout because the .modal-backdrop isn't created when the event show.bs.modal is triggered.

$(document).on('show.bs.modal', '.modal', function () {    var zIndex = 1040 + (10 * $('.modal:visible').length);    $(this).css('z-index', zIndex);    setTimeout(function() {        $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');    }, 0);});
  • This works for every .modal created on the page (even dynamic modals)
  • The backdrop instantly overlays the previous modal

Example jsfiddle

If you don't like the hardcoded z-index for any reason you can calculate the highest z-index on the page like this:

var zIndex = Math.max.apply(null, Array.prototype.map.call(document.querySelectorAll('*'), function(el) {  return +el.style.zIndex;})) + 10;

Scrollbar fix
If you have a modal on your page that exceeds the browser height, then you can't scroll in it when closing an second modal. To fix this add:

$(document).on('hidden.bs.modal', '.modal', function () {    $('.modal:visible').length && $(document.body).addClass('modal-open');});

Versions
This solution is tested with bootstrap 3.1.0 - 3.3.5


I realize an answer has been accepted, but I strongly suggest not hacking bootstrap to fix this.

You can pretty easily achieve the same effect by hooking the shown.bs.modal and hidden.bs.modal event handlers and adjusting the z-index there.

Here's a working example

A bit more info is available here.

This solution works automatically with arbitrarily deeply stacks modals.

The script source code:

$(document).ready(function() {    $('.modal').on('hidden.bs.modal', function(event) {        $(this).removeClass( 'fv-modal-stack' );        $('body').data( 'fv_open_modals', $('body').data( 'fv_open_modals' ) - 1 );    });    $('.modal').on('shown.bs.modal', function (event) {        // keep track of the number of open modals        if ( typeof( $('body').data( 'fv_open_modals' ) ) == 'undefined' ) {            $('body').data( 'fv_open_modals', 0 );        }        // if the z-index of this modal has been set, ignore.        if ($(this).hasClass('fv-modal-stack')) {            return;        }        $(this).addClass('fv-modal-stack');        $('body').data('fv_open_modals', $('body').data('fv_open_modals' ) + 1 );        $(this).css('z-index', 1040 + (10 * $('body').data('fv_open_modals' )));        $('.modal-backdrop').not('.fv-modal-stack').css('z-index', 1039 + (10 * $('body').data('fv_open_modals')));        $('.modal-backdrop').not('fv-modal-stack').addClass('fv-modal-stack');     });        });


Combining A1rPun's answer with the suggestion by StriplingWarrior, I came up with this:

$(document).on({    'show.bs.modal': function () {        var zIndex = 1040 + (10 * $('.modal:visible').length);        $(this).css('z-index', zIndex);        setTimeout(function() {            $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');        }, 0);    },    'hidden.bs.modal': function() {        if ($('.modal:visible').length > 0) {            // restore the modal-open class to the body element, so that scrolling works            // properly after de-stacking a modal.            setTimeout(function() {                $(document.body).addClass('modal-open');            }, 0);        }    }}, '.modal');

Works even for dynamic modals added after the fact, and removes the second-scrollbar issue. The most notable thing that I found this useful for was integrating forms inside modals with validation feedback from Bootbox alerts, since those use dynamic modals and thus require you to bind the event to document rather than to .modal, since that only attaches it to existing modals.

Fiddle here.