Direct Answers
- No built-in configuration propagates a backdrop click to underlying modals. Bootstrap 5 treats each modal independently; the topmost backdrop receives the click and hides only its own modal.
- Yes. Set
data-bs-backdrop="static" on nested modals to disable their backdrop-click dismissal while keeping keyboard: true (default) for Esc and close-button behavior.
- No dedicated "backdrop click" event exists. The closest hooks are
hide.bs.modal (fires before the topmost modal hides) and hidePrevented.bs.modal (fires when a click is ignored because backdrop: 'static'). Use these to implement custom propagation.
Default Behavior (Bootstrap 5.0–5.3)
When a second modal opens, Bootstrap inserts a new .modal-backdrop with a higher z-index. A click on that backdrop triggers hide only on the topmost modal. The lower modal remains in the DOM, hidden but still present. Focus trapping is managed per instance; when the topmost modal closes, focus returns to its trigger element (or the previous modal's trigger if you sequence hides correctly).
Workaround: Dismiss All Modals on Backdrop Click
Listen for hide.bs.modal on the topmost modal and programmatically hide any other visible modals. In Bootstrap 5.3+, .modal('hide') returns a Promise, allowing safe sequencing.
const topModalEl = document.getElementById('modalB');
const lowerModalEl = document.getElementById('modalA');
topModalEl.addEventListener('hide.bs.modal', () => {
const lowerInstance = bootstrap.Modal.getOrCreateInstance(lowerModalEl);
if (lowerInstance._isShown) { // internal flag; see verification
lowerInstance.hide();
}
});
Caution: Calling hide() on multiple modals in rapid succession can cause focus/aria inconsistencies. Await the Promise (5.3+) or chain via hidden.bs.modal callbacks.
Workaround: Disable Backdrop Click on Nested Modals Only
Add data-bs-backdrop="static" to the nested modal(s). The topmost modal keeps the default backdrop: true so its own backdrop click closes it. Esc and close buttons continue to work on all modals because keyboard is independent of backdrop.
<div class="modal" id="modalA" data-bs-backdrop="true">...</div>
<div class="modal" id="modalB" data-bs-backdrop="static">...</div>
With this setup, clicking modalB's backdrop fires hidePrevented.bs.modal on modalB (detail.reason === 'backdrop' in 5.3+), leaving both modals open.
Custom Propagation Logic
Intercept hidePrevented.bs.modal on a static modal to decide whether to close the stack:
modalB.addEventListener('hidePrevented.bs.modal', (e) => {
if (e.detail?.reason === 'backdrop') {
// Custom logic: close all, or only topmost, etc.
bootstrap.Modal.getOrCreateInstance(modalA).hide();
bootstrap.Modal.getOrCreateInstance(modalB).hide();
}
});
Verification Steps (Safe, Scoped)
- Create a test page with two modals (modalA triggers modalB). Set
data-bs-backdrop="true" on both. Open modalA, then modalB. Click modalB's backdrop → only modalB closes. Confirm via console logs on hide.bs.modal / hidden.bs.modal.
- Change modalB to
data-bs-backdrop="static". Click its backdrop → hidePrevented.bs.modal fires on modalB, modalB stays open. Verify event.detail.reason === 'backdrop' (5.3+).
- Implement a
hide.bs.modal listener on modalB that calls Modal.getOrCreateInstance(modalA).hide(). Observe both modals close. Check focus returns to modalA's trigger element.
- Test Esc key: with
keyboard: true (default), pressing Esc closes the topmost modal regardless of backdrop setting. Confirm hidePrevented.bs.modal does not fire for Esc when backdrop: 'static'.
- Verify Bootstrap version:
bootstrap.Modal.VERSION in console. Behavior described applies to 5.0–5.3; 5.3 added Promise returns on .modal('hide') and detail.reason on hidePrevented.
Assumptions and Uncertainty
- Assumes Bootstrap 5.0–5.3. Behavior may differ in 4.x or future 6.x.
- The internal
_isShown flag used in the example is not part of the public API; a safer check is tracking visibility via your own state or listening to shown.bs.modal/hidden.bs.modal.
- Deep nesting (more than 2–3 levels) is not officially supported and may produce z-index conflicts, scrollbar padding issues, and focus trap collisions.
One Diagnostic Detail Needed
Which Bootstrap 5 minor version are you targeting (5.0, 5.1, 5.2, 5.3)? The Promise return on .modal('hide') and detail.reason on hidePrevented are 5.3+ features; if you're on an earlier minor, the sequencing approach must use event callbacks instead.