Site icon Ampersand Tutorials

Bootstrap 5 Modal: Complete Guide with Examples

Quick answer: A Bootstrap 5 modal is a dialog built from three classes — modal, modal-dialog and modal-content — opened by a trigger with data-bs-toggle="modal" and data-bs-target="#id". The JavaScript is already in bootstrap.bundle.min.js, so no extra code is needed to open, close or animate it. The three mistakes that break most modals are a missing bundle script, a data-bs-target that does not match the dialog’s id, and Bootstrap 4 code that still uses the data-toggle prefix.

If you have not added the framework yet, start with getting started with Bootstrap 5 — this guide assumes the two CDN lines are already on the page.

The complete modal in 3 steps

Everything a working dialog needs: a trigger button, the modal markup, and a close button. No custom JavaScript at all.

<!-- Step 1: the trigger -->
<button type="button" class="btn btn-primary"
        data-bs-toggle="modal" data-bs-target="#deleteModal">
  Delete record
</button>

<!-- Step 2: the modal markup (place anywhere in the body) -->
<div class="modal fade" id="deleteModal" tabindex="-1"
     aria-labelledby="deleteModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="deleteModalLabel">Delete this record?</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"
                aria-label="Close"></button>
      </div>
      <div class="modal-body">
        This action cannot be undone.
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary"
                data-bs-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-danger">Delete</button>
      </div>
    </div>
  </div>
</div>

<!-- Step 3: the bundle (already required for the navbar) -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

Two attributes do most of the work. data-bs-toggle="modal" tells Bootstrap the element opens a dialog, and data-bs-target points at its id. The fade class on the wrapper adds the CSS transition; leave it off for an instant, un-animated open. Because the trigger is a button, pressing Enter on a keyboard works with no extra markup.

Modal options that matter

OptionAttributeWhat it does
Static backdropdata-bs-backdrop="static"Clicking outside will not close it
Ignore keyboarddata-bs-keyboard="false"Esc will not close it
Vertical centermodal-dialog-centeredCenters the dialog in the viewport
Scrollable bodymodal-dialog-scrollableLong content scrolls inside the dialog
Small / large / XLmodal-sm / modal-lg / modal-xlWidth of the dialog
Fullscreenmodal-fullscreenCovers the whole viewport, or use modal-fullscreen-sm-down

The size classes go on the modal-dialog div, not the outer wrapper — the most common reason a modal refuses to grow. Combine them with centering for a login box: <div class="modal-dialog modal-dialog-centered modal-sm">.

Opening and closing from JavaScript

Trigger attributes cover the click case, but sometimes you need to open a dialog from code — after a form submits, on a timer, or from a button rendered at runtime. Create the instance once and call its methods:

// grab (or create) the instance
const modalEl = document.getElementById('deleteModal');
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);

modal.show();   // open
modal.hide();   // close
modal.toggle(); // flip state
modal.dispose(); // remove listeners (single-page apps)

// react to the lifecycle
modalEl.addEventListener('hidden.bs.modal', () => {
  console.log('dialog finished closing');
});

The event chain is show.bs.modal → shown.bs.modal → hide.bs.modal → hidden.bs.modal. Use show.bs.modal to inject fresh data and hidden.bs.modal to clear it, so the next open never shows stale values. Prefer the option form when you need a static backdrop: new bootstrap.Modal(el, { backdrop: 'static', keyboard: false }).

When the modal does not open: check these four things

Coming from the other big framework? The Materialize modal guide covers the same component with an init-based API — a useful side-by-side if you support both. A modal that collects input usually wraps a form; the field markup from our Bootstrap forms and validation guide drops straight into modal-body.

Want an instructor to review your dialog-heavy interfaces with you? Ampersand Academy teaches front-end development one-to-one, using your own project as the curriculum.

Frequently asked questions

Why is my Bootstrap 5 modal not opening?

Almost always one of three things: the bootstrap.bundle.min.js script is missing so no JavaScript wires the trigger, the data-bs-target value does not exactly match the modal’s id, or the markup still uses the Bootstrap 4 data-toggle prefix. Check all three in that order.

How do I stop a Bootstrap modal from closing when I click outside it?

Add data-bs-backdrop to the modal wrapper with the value static, or pass the backdrop option set to static when creating it in JavaScript. Add data-bs-keyboard set to false as well if you also want to disable the Esc key.

How do I open a Bootstrap modal with JavaScript?

Get an instance with bootstrap.Modal.getOrCreateInstance(element) and call its show() method. The same object exposes hide() and toggle(). Create it once and reuse it rather than building a new instance on every click.

How do I change the size of a Bootstrap modal?

Add modal-sm, modal-lg or modal-xl to the modal-dialog div. For a dialog that fills the viewport use modal-fullscreen, or a responsive variant such as modal-fullscreen-sm-down to go fullscreen only on small screens.

What is the difference between data-toggle and data-bs-toggle?

data-toggle was the Bootstrap 4 attribute; Bootstrap 5 renamed every component attribute to the data-bs- prefix, so data-bs-toggle is the v5 name. If an old snippet does nothing on Bootstrap 5, the prefix is the reason.

Exit mobile version