Multiple modals overlay

314,461

Solution 1

Solution inspired by the answers of @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() {
  const zIndex = 1040 + 10 * $('.modal:visible').length;
  $(this).css('z-index', zIndex);
  setTimeout(() => $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'));
});
  • This works for every .modal created on the page (even dynamic modals)
  • The backdrop instantly overlays the previous modal

Example jsfiddle

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

const zIndex = 10 +
  Math.max(...Array.from(document.querySelectorAll('*')).map((el) => +el.style.zIndex));

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',
  () => $('.modal:visible').length && $(document.body).addClass('modal-open'));

Versions
This solution is tested with bootstrap 3.1.0 - 3.3.5

Solution 2

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'); 

    });        
});

Solution 3

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.

Solution 4

Something shorter version based off Yermo Lamers' suggestion, this seems to work alright. Even with basic animations like fade in/out and even crazy batman newspaper rotate. http://jsfiddle.net/ketwaroo/mXy3E/

$('.modal').on('show.bs.modal', function(event) {
    var idx = $('.modal:visible').length;
    $(this).css('z-index', 1040 + (10 * idx));
});
$('.modal').on('shown.bs.modal', function(event) {
    var idx = ($('.modal:visible').length) -1; // raise backdrop after animation.
    $('.modal-backdrop').not('.stacked').css('z-index', 1039 + (10 * idx));
    $('.modal-backdrop').not('.stacked').addClass('stacked');
});

Solution 5

A simple solution for Bootstrap 4.5

.modal.fade {
  background: rgba(0, 0, 0, 0.5);
}

.modal-backdrop.fade {
  opacity: 0;
}
Share:
314,461

Related videos on Youtube

Willian Bonho Daiprai
Author by

Willian Bonho Daiprai

Updated on July 08, 2022

Comments

  • Willian Bonho Daiprai
    Willian Bonho Daiprai almost 2 years

    I need that the overlay shows above the first modal, not in the back.

    Modal overlay behind

    $('#openBtn').click(function(){
    	$('#myModal').modal({show:true})
    });
    <a data-toggle="modal" href="#myModal" class="btn btn-primary">Launch modal</a>
    
    <div class="modal" id="myModal">
    	<div class="modal-dialog">
          <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
              <h4 class="modal-title">Modal title</h4>
            </div><div class="container"></div>
            <div class="modal-body">
              Content for the dialog / modal goes here.
              <br>
              <br>
              <br>
              <br>
              <br>
              <a data-toggle="modal" href="#myModal2" class="btn btn-primary">Launch modal</a>
            </div>
            <div class="modal-footer">
              <a href="#" data-dismiss="modal" class="btn">Close</a>
              <a href="#" class="btn btn-primary">Save changes</a>
            </div>
          </div>
        </div>
    </div>
    <div class="modal" id="myModal2" data-backdrop="static">
    	<div class="modal-dialog">
          <div class="modal-content">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
              <h4 class="modal-title">Second Modal title</h4>
            </div><div class="container"></div>
            <div class="modal-body">
              Content for the dialog / modal goes here.
            </div>
            <div class="modal-footer">
              <a href="#" data-dismiss="modal" class="btn">Close</a>
              <a href="#" class="btn btn-primary">Save changes</a>
            </div>
          </div>
        </div>
    </div>
    
    
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js"></script>

    I tried to change the z-index of .modal-backdrop, but it becomes a mess.

    In some cases I have more than two modals on the same page.

  • Willian Bonho Daiprai
    Willian Bonho Daiprai over 10 years
    Ok, that's great, but I put a third modal and it not works. I have some scripts that generate it (like alerts, search boxes, etc) and I can have 3 opened modals at once (until i know). I'm not good with css, sorry if i loose something. There is the code: bootply.com/86975
  • Somnium
    Somnium almost 10 years
    Cool, however when one modal is closed, there appears two scrollbars -one for modal, second for whole page. Can be this solved?
  • Yermo Lamers
    Yermo Lamers almost 10 years
    Are you using the latest bootstrap?
  • Somnium
    Somnium almost 10 years
    Yes, you can see this in that example too if you download it and add a lot of text inside page.
  • StriplingWarrior
    StriplingWarrior over 9 years
    One problem that remains here is that if you close out the second modal and your page has enough text to exceed the browser size, you end up with weird scrollbar behavior. You have to also restore the modal-open class on the body element: jsfiddle.net/vkyjocyn
  • Lee
    Lee over 9 years
    To deal with the extra scoll bar on close, you need to add class "modal-open" to the body in the hidden.bs.modal listener.
  • ScubaSteve
    ScubaSteve over 9 years
    One issue I ran into was when the first modal was showing and needed a scrollbar, if I showed a second modal, it would remove the first modal's scrollbar and I was stuck with a clipped modal. To solve this, I just added this to my CSS, .modal { overflow-y: auto; }
  • harco gijsbers
    harco gijsbers over 9 years
    May i suggest using the max z index of the open modals to determine the base z-index instead of the hardcoded value of 1040 ? stackoverflow.com/a/5680815/2569159
  • A1rPun
    A1rPun about 8 years
    Nice solution. I expect the backdrop to go darker when you have multiple modals but I can see why you wouldn't want it. @AndyBurton Can you please let me know what my solution is missing?
  • Andy Burton
    Andy Burton about 8 years
    @A1rPun upon opening and closing the 2nd modal the scroll bars which allowed scrolling in the 1st modal were removed. IIRC this looked to be because the class on the body was removed when the 2nd modal was closed.
  • A1rPun
    A1rPun about 8 years
    @AndyBurton I handle the solution to that problem as well.
  • Vishal
    Vishal over 7 years
    @A1rPun not working for me.. when i close the second modal.. the body become scrollable.. i used all your code.. :(
  • metamagikum
    metamagikum over 7 years
    Not worked in my environment with latest bs. I had to do: $('.modal-backdrop').last().not('.modal-stack').css('z-index‌​', zIndex - 1).addClass('modal-stack');
  • FluffyKitten
    FluffyKitten over 6 years
    Code-only answers are often unhelpful in pointing to why the issue happened. You should include an explanation why it solves the issue. Please read How do I write a good answer?
  • benrwb
    benrwb about 6 years
    I had to make a minor change (added .not(this) to the second line) to get it working with bootstrap datepicker var zIndex = 1040 + (10 * $('.modal:visible').not(this).length);
  • Diego Jancic
    Diego Jancic about 6 years
    Works well. I had to change the way it attaches to events to this form $(document).on('---event---', '.modal', function() ... instead of $('.modal').on('---event---', ...) because the content was rendered after the document ready event.
  • Matthew Goheen
    Matthew Goheen over 5 years
    I feel like this should be the accepted answer. Works flawlessly for me.
  • sanjeev shetty
    sanjeev shetty over 4 years
    I Loved it. Addon to this, $('.modal:visible').length && $(document.body).addClass('modal-open'); in hidden.bs.modal function
  • Murphybro2
    Murphybro2 about 4 years
    If two modals exist, then the first is removed and a third is added, the third will have the same z-index as the second as they both used a length of 2. I needed to factor in the last used z-index across the modals.
  • wobsoriano
    wobsoriano about 4 years
    Works fine with BS4 latest
  • Ben in CA
    Ben in CA almost 4 years
    This seems to work good... you'd think this would be standard Bootstrap?
  • Captain Squirrel
    Captain Squirrel almost 4 years
    Worked perfectly for me
  • Matt Drouillard
    Matt Drouillard over 3 years
    You're a genius, this is incredible; if I could buy you a beer I would; Cheers.
  • kite
    kite over 3 years
    I combined your css with javascript fixes for bootstrap multiple modal not scrolling issue github.com/nakupanda/bootstrap3-dialog/issues/…, the stackOverflow issue: stackoverflow.com/a/64662694/423356
  • Ugo
    Ugo over 3 years
    Worked for me, but I also got a second scroll bar appearing.
  • Nalin Jayasuriya
    Nalin Jayasuriya about 3 years
    This solution works for Bootstrap 5 as well. Thank you Ricardo!
  • Gorelov Grigory
    Gorelov Grigory almost 3 years
    Besto solution for me using BS5.
  • ɐsɹǝʌ ǝɔıʌ
    ɐsɹǝʌ ǝɔıʌ over 2 years
    Superb! Works like a charm.
  • Tahir Alvi
    Tahir Alvi over 2 years
    Works fine with bs4 in Dec 2021 even. Thanks @A1rPun
  • Mu-Tsun Tsai
    Mu-Tsun Tsai over 2 years
    Wow this is crazy simple! Bootstrap team really should just use this!
  • Nicholas
    Nicholas about 2 years
    You just saved me (Vuejs, bootstrap5, nested modals)
  • Jorge Wander Santana Ureña
    Jorge Wander Santana Ureña almost 2 years
    considere adding ``
  • A1rPun
    A1rPun almost 2 years
    @JorgeWanderSantanaUreña I'm not sure what you mean, I'm not doing any interpolation.
  • Jorge Wander Santana Ureña
    Jorge Wander Santana Ureña almost 2 years
    my bad, ignore my comment.
  • nfplee
    nfplee almost 2 years
    This no longer works as of Bootstap 5.1. See github.com/twbs/bootstrap/issues/34982 for more information.