Components

Bootstrap Modal: Sizes, Centering, Forms and JavaScript

By the bootstrap.build team · 6 min read · Published

A Bootstrap modal is a dialog box that opens on top of the page and dims everything behind it: a confirmation (“Delete this project?”), a sign-up form, an image preview, or a video. The modal plugin handles the backdrop, keyboard focus, the Escape key, and scroll locking, so you only write the markup. This guide covers that markup, opening and closing a modal, sizes (including the new extra-extra-large size in Bootstrap 5.3.9), centered, scrolling and fullscreen modals, forms inside modals, the JavaScript API, and the problems people hit most often.

A working modal

<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#delete-modal">
  Delete project
</button>

<div class="modal fade" id="delete-modal" tabindex="-1" aria-labelledby="delete-modal-title" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h1 class="modal-title fs-5" id="delete-modal-title">Delete this project?</h1>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        The project and its 12 pages will be removed. This can't 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>

Load Bootstrap’s JavaScript (bootstrap.bundle.min.js or bootstrap.min.js, since modals don’t need Popper). Unlike tooltips, modals work from data attributes alone, with no initialization code.

Part Job
data-bs-toggle="modal" and data-bs-target Make any button open the modal with that id
.modal The full-screen layer that holds the dialog; .fade adds the animation
.modal-dialog Sets the width and position
.modal-content The white box with the border and shadow
.modal-header, .modal-body, .modal-footer The three optional sections
data-bs-dismiss="modal" Makes a button close the modal

tabindex="-1" lets the modal receive focus, and aria-labelledby points screen readers to the title. Bootstrap moves focus into the modal when it opens and back to the button when it closes.

Sizes

Add a size class to .modal-dialog:

Class Max width Applies from
modal-sm 300px 576px screens
(none) 500px 576px screens
modal-lg 800px 992px screens
modal-xl 1140px 1200px screens
modal-xxl 1320px 1400px screens (new in 5.3.9)
<div class="modal-dialog modal-lg">...</div>

On smaller screens every modal is full width minus a small margin. modal-xxl arrived in Bootstrap 5.3.9; on older 5.3 versions, use modal-xl or set a custom width with the --bs-modal-width variable:

.modal-wide { --bs-modal-width: 960px; }

Vertically centered

<div class="modal-dialog modal-dialog-centered">...</div>

By default a modal sits near the top of the screen. modal-dialog-centered puts it in the middle, which suits short confirmations.

Long content that scrolls

When the content is longer than the screen, the whole modal scrolls with the page. To keep the header and footer in place and scroll only the body, add modal-dialog-scrollable:

<div class="modal-dialog modal-dialog-scrollable">...</div>

This is the better choice for terms of service or long forms, because the action buttons stay visible.

Fullscreen modals

<div class="modal-dialog modal-fullscreen">...</div>
<div class="modal-dialog modal-fullscreen-md-down">...</div>

modal-fullscreen always covers the screen. The responsive versions, from modal-fullscreen-sm-down to modal-fullscreen-xxl-down, go fullscreen only below that breakpoint, which works well for forms on phones. The breakpoint values are in the breakpoints guide.

A modal that doesn’t close on outside click

By default, clicking the backdrop or pressing Escape closes the modal. For a step people must finish or cancel explicitly, turn both off:

<div class="modal fade" id="terms-modal" data-bs-backdrop="static" data-bs-keyboard="false"
  tabindex="-1" aria-labelledby="terms-title" aria-hidden="true">

With a static backdrop, a click outside makes the modal bounce briefly instead of closing. Always keep a visible button that closes it.

A form inside a modal

Wrap the content in a <form> so Enter submits it and the submit button sits in the footer:

<div class="modal fade" id="invite-modal" tabindex="-1" aria-labelledby="invite-title" aria-hidden="true">
  <div class="modal-dialog">
    <form class="modal-content" id="invite-form">
      <div class="modal-header">
        <h1 class="modal-title fs-5" id="invite-title">Invite a teammate</h1>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <label for="invite-email" class="form-label">Email</label>
        <input type="email" class="form-control" id="invite-email" required>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
        <button type="submit" class="btn btn-primary">Send invite</button>
      </div>
    </form>
  </div>
</div>

The autofocus attribute doesn’t work inside modals, because the modal isn’t visible when the page loads. Focus the field once the modal has opened:

const inviteModal = document.querySelector('#invite-modal')
inviteModal.addEventListener('shown.bs.modal', () => {
  document.querySelector('#invite-email').focus()
})

Form layout, validation, and input groups are covered in the Bootstrap forms guide.

Open and close a modal with JavaScript

const modal = bootstrap.Modal.getOrCreateInstance('#delete-modal')
modal.show()
modal.hide()
modal.toggle()

To close the modal after a form is sent:

document.querySelector('#invite-form').addEventListener('submit', async (event) => {
  event.preventDefault()
  await fetch('/api/invite', { method: 'POST', body: new FormData(event.target) })
  bootstrap.Modal.getInstance('#invite-modal').hide()
})

To open a modal when the page loads, call show() once the page is ready, for example bootstrap.Modal.getOrCreateInstance('#welcome-modal').show() at the end of the page. Use this sparingly: modals that appear without a click annoy visitors and can hurt mobile search rankings.

One modal, different content

For a list of items that each open the same modal with different details, read the clicked button from event.relatedTarget:

<button class="btn btn-link" data-bs-toggle="modal" data-bs-target="#user-modal" data-user="Ana Lopez">Ana</button>
<button class="btn btn-link" data-bs-toggle="modal" data-bs-target="#user-modal" data-user="Ben Carter">Ben</button>
document.querySelector('#user-modal').addEventListener('show.bs.modal', (event) => {
  const name = event.relatedTarget.getAttribute('data-user')
  event.target.querySelector('.modal-title').textContent = name
})

Events

Event Fires
show.bs.modal When opening starts; call event.preventDefault() to cancel
shown.bs.modal When the modal is fully visible
hide.bs.modal When closing starts; can also be cancelled
hidden.bs.modal When the modal is fully hidden
hidePrevented.bs.modal When a static modal blocks a close attempt

Style modals

Modals use CSS variables:

.modal {
  --bs-modal-border-radius: 1rem;
  --bs-modal-padding: 1.5rem;
  --bs-modal-header-border-color: transparent;
  --bs-modal-footer-border-color: transparent;
}
.modal-backdrop { --bs-backdrop-opacity: .7; }

In Sass, $modal-inner-padding, $modal-content-border-radius, $modal-backdrop-opacity (0.5), and the size variables $modal-sm to $modal-xxl set the defaults. Modals follow dark mode on their own.

Common modal problems

The modal opens behind the gray backdrop. The modal is inside an element with position: fixed, transform, or a z-index, such as a fixed navbar. Move the modal markup to just before </body>.

Nothing happens on click. Bootstrap’s JavaScript isn’t loaded, or the data-bs-target doesn’t match the modal’s id. Check the browser console for errors.

The modal opens and immediately closes. Bootstrap’s JavaScript is loaded twice, for example from a CDN and from your bundle. Keep one copy.

The old attributes don’t work. Bootstrap 5 uses data-bs-toggle, data-bs-target, and data-bs-dismiss. The Bootstrap 4 names without bs- do nothing.

The page jumps when the modal opens. Bootstrap hides the page scrollbar and adds padding to make up for it. Fixed elements need the same padding; Bootstrap adjusts .fixed-top, .fixed-bottom, and .sticky-top automatically, and any element with the is-fixed class, so add is-fixed to your other fixed elements.

FAQ

How do I open a Bootstrap modal with a button?

Add data-bs-toggle="modal" and data-bs-target="#your-modal-id" to the button, and make sure Bootstrap’s JavaScript is loaded. No initialization code is needed. To open it from JavaScript, call bootstrap.Modal.getOrCreateInstance('#your-modal-id').show().

How do I center a Bootstrap modal vertically?

Add the modal-dialog-centered class to the .modal-dialog element. Combine it with modal-dialog-scrollable if the content can be longer than the screen.

How do I change the width of a Bootstrap modal?

Add modal-sm (300px), modal-lg (800px), modal-xl (1140px), or modal-xxl (1320px, new in Bootstrap 5.3.9) to .modal-dialog. For any other width, set the --bs-modal-width CSS variable on the modal.

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

Add data-bs-backdrop="static" to the .modal element, and data-bs-keyboard="false" to also ignore the Escape key. Keep a close or cancel button so people can still leave.

Why does my Bootstrap modal appear behind the backdrop?

A parent element has position: fixed, a transform, or a z-index that traps the modal below the backdrop. Move the modal’s markup out of that element, ideally to just before the closing </body> tag.

Try it in the builder

Make these changes visually with a live preview, then export clean Bootstrap Sass or CSS.

Open the Builder