A decade of Canvas at your command — powered by our custom AI engineStart Building →
Bootstrap 5April 25, 2026·7 min read

Bootstrap 5 Modal Components: Building Popup Dialogues

Popup dialogues are one of the most versatile UI patterns on the web — used for confirmations, forms, image previews, and notifications — yet many developers implement them poorly, either blocking the page incorrectly or relying on outdated JavaScript libraries. Bootstrap 5 solves this cleanly with its built-in modal component, requiring no third-party dependencies and giving you full control over structure, behaviour, and accessibility.

Key Takeaways

  • Bootstrap 5 modals are fully self-contained — no jQuery or third-party plugins required, just the bundled Bootstrap JS.
  • Modal size, scrolling behaviour, and backdrop options are all controlled through data attributes and CSS utility classes.
  • Stacking multiple modals or nesting a form inside a modal are common patterns that require specific structural decisions to work correctly.
  • When using the Canvas HTML Template, Bootstrap 5 is already bundled — never load the Bootstrap CDN separately alongside it.

How the Bootstrap 5 Modal Component Works

The Bootstrap 5 modal is a layered dialog system that consists of three structural parts: the modal wrapper (.modal), the dialog container (.modal-dialog), and the content box (.modal-content). When triggered, Bootstrap adds a backdrop overlay, applies overflow: hidden to the body to prevent scroll, and shifts focus to the modal for accessibility compliance.

Triggering a modal requires either a data attribute on a button or programmatic invocation via JavaScript. The data attribute approach is the most common and requires zero custom JS:

<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
  Open Modal
</button>

<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal Title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p>Your modal content goes here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save Changes</button>
      </div>
    </div>
  </div>
</div>

The tabindex="-1" attribute on the outer .modal div ensures the element receives focus when opened without being part of the natural tab order when closed. This is a required accessibility detail, not optional.

a computer screen with the words the easy way to build marketplaces
Photo by Team Nocoloco on Unsplash

Bootstrap 5 provides five size modifier classes applied to the .modal-dialog element. Choosing the right size prevents the common mistake of cramming too much content into a default-width modal or leaving a simple confirmation dialogue feeling oversized.

  • .modal-sm — 300px max-width, ideal for simple confirmations or alerts
  • .modal-lg — 800px max-width, suitable for forms or preview panels
  • .modal-xl — 1140px max-width, for data tables or detailed content
  • .modal-fullscreen — occupies the entire viewport
  • .modal-fullscreen-{breakpoint}-down — fullscreen below a specific breakpoint, useful for mobile UX

A common pattern for mobile-first projects is the responsive fullscreen variant, which keeps the modal at a fixed size on desktop while expanding to fullscreen on smaller screens:

<div class="modal-dialog modal-lg modal-fullscreen-md-down">
  <!-- modal-content here -->
</div>

If you are working on responsive layout decisions more broadly, the principles covered in Bootstrap 5 Breakpoints: How to Build Truly Responsive Layouts apply directly to modal sizing choices at different viewports.

Scrollable and Vertically Centred Modals

By default, a modal that exceeds the viewport height will scroll the entire page. Adding .modal-dialog-scrollable changes this behaviour so that the .modal-body scrolls internally while the header and footer remain fixed — essential for forms with many fields or long terms-and-conditions text.

Vertical centring is handled by .modal-dialog-centered, which positions the dialogue in the middle of the viewport rather than near the top. These two modifier classes can be combined:

<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
  <div class="modal-content">
    <div class="modal-header">
      <h5 class="modal-title">Terms and Conditions</h5>
      <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
    </div>
    <div class="modal-body">
      <p>Long scrollable content here...</p>
    </div>
    <div class="modal-footer">
      <button type="button" class="btn btn-success" data-bs-dismiss="modal">I Agree</button>
    </div>
  </div>
</div>
a window with a sign that says we're setting up a new show
Photo by Rapha Wilde on Unsplash

One of the most practical uses of a Bootstrap popup is a contact or lead-capture form that appears without navigating away from the current page. The key structural rule is to place the <form> tag inside .modal-content but wrapping both .modal-body and .modal-footer, so the submit button in the footer remains part of the form:

<div class="modal fade" id="contactModal" tabindex="-1" aria-labelledby="contactModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <form action="/submit" method="POST">
        <div class="modal-header">
          <h5 class="modal-title" id="contactModalLabel">Get in Touch</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <div class="mb-3">
            <label for="nameInput" class="form-label">Full Name</label>
            <input type="text" class="form-control" id="nameInput" name="name" required>
          </div>
          <div class="mb-3">
            <label for="emailInput" class="form-label">Email Address</label>
            <input type="email" class="form-control" id="emailInput" name="email" required>
          </div>
        </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 Message</button>
        </div>
      </form>
    </div>
  </div>
</div>

This pattern is frequently used on landing pages and SaaS product sites — if you are building that type of page, the post on How to Build an AI SaaS Landing Page with Canvas HTML Template shows how these components fit into a complete page structure.

Controlling Modals Programmatically with JavaScript

Data attributes handle most use cases, but there are situations — such as showing a modal after an AJAX call completes or dismissing it after successful form validation — where you need programmatic control via the Bootstrap Modal JavaScript API.

Bootstrap 5 exposes a clean API through bootstrap.Modal. The three most used methods are show(), hide(), and toggle():

const modalElement = document.getElementById('contactModal');
const modal = new bootstrap.Modal(modalElement, {
  backdrop: 'static',
  keyboard: false
});

modal.show();

modalElement.addEventListener('hidden.bs.modal', () => {
  console.log('Modal has been fully hidden');
});

The backdrop: 'static' option prevents the modal from closing when the user clicks outside it — a necessary UX decision for critical confirmations or multi-step forms where accidental dismissal would cause data loss. The keyboard: false option disables the Escape key dismissal for the same reason.

Bootstrap 5 also fires lifecycle events — show.bs.modal, shown.bs.modal, hide.bs.modal, and hidden.bs.modal — that let you hook into the open and close transitions to reset form state, load content dynamically, or trigger analytics events.

Using Bootstrap Modals Inside the Canvas HTML Template

Because the Canvas HTML Template is built on Bootstrap 5 with its own bundled JS files (js/plugins.min.js and js/functions.bundle.js), Bootstrap modal functionality is available on every Canvas page without any additional setup. You must not load the Bootstrap CDN separately — doing so will cause script conflicts and modal failures.

To style a modal to match Canvas theme colours, target the .modal-content element using the Canvas CSS variable --cnvs-themecolor rather than Bootstrap’s utility colours:

.modal-content {
  border-top: 3px solid var(--cnvs-themecolor);
}

.modal .btn-primary {
  background-color: var(--cnvs-themecolor);
  border-color: var(--cnvs-themecolor);
}

This approach keeps your modal styling consistent with the rest of the Canvas theme and ensures it updates automatically whenever you change --cnvs-themecolor globally. For a broader look at how Bootstrap components and Canvas work together in team environments, the post on Canvas HTML Template for Agencies: Workflows, Prompts, and Best Practices is worth reading alongside this one.

If you want to compare how Bootstrap 5 components like modals fit into the wider landscape of CSS frameworks, the detailed breakdown in Bootstrap 5 vs Tailwind CSS: Which Should You Use for HTML Templates? covers the trade-offs well.

Frequently Asked Questions

Can I have multiple modals open at the same time in Bootstrap 5?

Bootstrap 5 does not support multiple simultaneously open modals by default. You can open a second modal after closing the first, but stacking two modals on screen at the same time requires custom CSS and JavaScript to manage z-index and backdrop layering manually. For most projects, chaining modals sequentially is the cleaner approach.

Why is my Bootstrap modal not working when I include it in a Canvas HTML Template page?

The most common cause is loading Bootstrap JS from a CDN in addition to Canvas’s bundled scripts. Canvas includes Bootstrap 5 inside js/plugins.min.js — adding a second copy of Bootstrap creates conflicts that break modal initialisation. Remove any separate Bootstrap CDN script tags and rely solely on Canvas’s own JS files.

How do I prevent a Bootstrap modal from closing when clicking the backdrop?

Pass backdrop: 'static' as an option when initialising the modal via JavaScript: new bootstrap.Modal(el, { backdrop: 'static' }). You can also use the data attribute approach: add data-bs-backdrop="static" to the outer .modal element.

Is the Bootstrap 5 modal component accessible?

Yes, when implemented correctly. The component manages focus trapping automatically, moves focus into the modal on open, returns focus to the trigger element on close, and respects the aria-hidden attribute on the backdrop. You must include tabindex="-1" on the outer .modal div, aria-labelledby pointing to the modal title, and a proper close button with an aria-label to meet WCAG 2.1 AA requirements.

Can I load content into a Bootstrap modal dynamically via AJAX?

Yes. Listen for the show.bs.modal event, make your AJAX request inside the handler, and inject the response HTML into the .modal-body element before the modal finishes opening. Use the shown.bs.modal event if you need the modal fully visible before injecting content, such as when initialising a chart or map inside the dialogue.

If you’re working with the Canvas HTML Template and want to generate production-ready layouts faster, try Canvas Builder free and see how much time you save on every project.

Related Posts