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.

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

  • No bundle script. Modals are JavaScript-driven. If only the CSS link is loaded, the button does nothing.
  • data-bs-target / id mismatch. #deleteModal must equal id="deleteModal" exactly — one typo and the click is ignored.
  • Bootstrap 4 attributes. data-toggle and data-target were renamed to data-bs-toggle and data-bs-target in v5. Old snippets silently do nothing.
  • Two copies of Bootstrap. Loading the bundle twice, or mixing a bundled copy with a separate Popper build, throws errors that stop every component on the page.

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.

Official documentation

For the full reference behind this guide, read the Bootstrap 5.3 modal documentation. It is the source the details above are drawn from, and the first place to check when an option or attribute name changes.

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.

Last updated on · Written by