Modal
The modal component can be used to create dialogs, user notifications, lightboxes, or completely custom content.
Create amazing Typeform-like forms and pages just by writing Markdown!
Overview #
Modals are built with HTML, CSS, and JavaScript. They're positioned over everything else in the document and remove scroll from the <body>
so that modal content scrolls instead. Here's a live example of a modal that can be opened by clicking on the button or the link. By default, clicking on the modal "backdrop" will automatically close the modal, but including a dedicated close button is recommended.
Open modal (it will slide down and fade in from the top)...
HTML
<!-- Modal toggles -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-1">
Launch modal
</button>
<a href="#example-modal-1" role="button" class="btn btn-link" data-bs-toggle="modal">
Launch modal
</a>
<!-- Modal -->
<div class="modal fade" id="example-modal-1" tabindex="-1" aria-labelledby="modal-title-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-1">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
This is the modal body which can contain all types of custom content, such as forms, tooltips, popovers, grids, etc.
</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</button>
</div>
</div>
</div>
</div>
A few things to note about modals:
- Modals use
position: fixed
, which can sometimes be a bit particular about its rendering. Whenever possible, place your modal HTML in a top-level position to avoid potential interference from other elements. You'll likely run into issues when nesting a.modal
within another fixed element. This positioning may also cause some minor issues on mobile phones. - The modal content is made up of header (
.modal-header
), body (.modal-body
) and footer (.modal-footer
) components. The header and body are required forpadding
, but the footer is optional. - Modals can be toggled using
data-bs-toggle="modal"
on a button or link, though buttons are generally recommended for being the ideal choice. The targeting is done usingdata-bs-target
for buttons, andhref
for links.
Accessibility #
Be sure to add aria-labelledby="..."
, referencing the modal title, to .modal
. Additionally, you may give a description of your modal dialog with aria-describedby
on .modal
. Note that you don't need to add role="dialog"
since we already add it via JavaScript.
Also note, the animation effect of this component is dependent on the prefers-reduced-motion
media query. See the reduced motion section of our accessibility documentation.
Static backdrop #
When backdrop is set to static (e.g., using data-bs-static="true"
), the modal will not close when clicking outside of it. Moreover, you can also disable esc key dismissal of modals (e.g., using data-bs-keyboard="false"
).
Open modal with static backdrop...
HTML
<!-- Modal toggle -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-2">
Launch modal
</button>
<!-- Modal with static backdrop -->
<div class="modal fade" id="example-modal-2" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="modal-title-2" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-2">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
This is the modal body which can contain all types of custom content, such as forms, tooltips, popovers, grids, etc.
</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</button>
</div>
</div>
</div>
</div>
Long scrolling content #
When modals become too long for the user's viewport or device, they scroll independent of the page itself. This is shown with the first modal in the example below. You can also create a scrollable modal that allows scrolling in the modal body by adding .modal-dialog-scrollable
to .modal-dialog
. This is shown with the second modal in the example below.
Open modals with long scrolling content...
HTML
<!-- Modal with long scrolling content (default body scrolling) -->
<div class="modal fade" id="example-modal-3" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
...
</div>
</div>
</div>
<!-- Modal with scrollable body -->
<div class="modal fade" id="example-modal-4" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
...
</div>
</div>
</div>
Vertically centered #
Add .modal-dialog-centered
to .modal-dialog
to vertically center the modal. This will also work for modals with scrollable bodies with modal-dialog-scrollable
.
Open vertically centered modal...
HTML
<!-- Vertically centered modal -->
<div class="modal fade" id="example-modal-5" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
...
</div>
</div>
</div>
Tooltips, popovers, and grid system #
Tooltips and popovers can be placed within modals as needed. When modals are closed, any tooltips and popovers within are also automatically dismissed. Moreover, you can also use the grid system within a modal by nesting .container-fluid
within the .modal-body
. Then, use the normal grid system classes as you would anywhere else.
Open modal with tooltip, popover, and grid...
HTML
<!-- Modal with tooltip, popover, and grid system -->
<div class="modal fade" id="example-modal-6" tabindex="-1" aria-labelledby="modal-title-6" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-6">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h5>Tooltip and popover</h5>
<p class="mb-2">
Here's <a href="#" data-bs-toggle="tooltip" data-bs-title="This is a tooltip">a link</a> with a tooltip inside the modal. You can also click on the following button to open a popover.
</p>
<div class="mb-4">
<button type="button" class="btn btn-primary" data-bs-toggle="popover" data-bs-title="Title of the popover" data-bs-content="Content of the popover that spans across multiple lines.">
Popover
</button>
</div>
<h5>Grid system</h5>
<p class="mb-2">
And here's an example of the grid system.
</p>
<div class="container-fluid g-0">
<div class="row">
<div class="col-4">4</div>
<div class="col-8">8</div>
</div>
<div class="row">
<div class="col-sm-8 mt-3">sm-8</div>
<div class="col-sm-4 mt-3">sm-4</div>
</div>
</div>
</div>
</div>
</div>
</div>
Forms and auto-focus #
You can also place forms inside modals. Please note, due to how HTML5 defines its semantics, the autofocus HTML attribute (opens in new tab) has no effect in modals. To achieve the same effect, use some custom JavaScript as shown in the example below.
Please sign in to continue...
HTML
<!-- Modal toggle -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-7">
Sign in
</button>
<!-- Modal with form -->
<div class="modal fade" id="example-modal-7" tabindex="-1" aria-labelledby="modal-title-7" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-7">
Sign in to your account
<br />
<small class="text-body-secondary fw-normal">Welcome back!</small>
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-3">
<label for="email" class="form-label">Email address</label>
<input type="email" class="form-control" id="email" placeholder="Email address">
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password">
</div>
<div class="mb-3 pb-3 border-bottom">
<button type="submit" class="btn btn-primary w-100">Sign in</button>
</div>
<div class="text-center text-body-secondary">
Don't have an account? <a href="#">Sign up</a>
</div>
</form>
</div>
</div>
</div>
</div>
JavaScript
// Auto-focus when modal is opened
const signInModal = document.getElementById("example-modal-7");
const inputToFocus = document.getElementById("email");
if (signInModal) {
signInModal.addEventListener("shown.bs.modal", () => {
if (inputToFocus) {
inputToFocus.focus();
}
});
}
Varying modal content #
Use event.relatedTarget
and the data-bs-*
attributes to vary the contents of the modal depending on which button was clicked to open it.
Open modal and send message to...
HTML
<!-- Modal toggles -->
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#example-modal-8" data-bs-recipient="@steve">
@steve
</button>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-8" data-bs-recipient="@harrison">
@harrison
</button>
<!-- Modal with form -->
<div class="modal fade" id="example-modal-8" tabindex="-1" aria-labelledby="modal-title-8" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-8">New message</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form>
<div class="mb-3">
<label for="recipient" class="form-label">Recipient</label>
<input type="text" class="form-control" id="recipient" placeholder="Recipient">
</div>
<div class="mb-3">
<label for="message" class="form-label">Message</label>
<textarea class="form-control" id="message" rows="3" placeholder="Type your message"></textarea>
</div>
<div class="text-end pt-3 border-top">
<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>
</div>
JavaScript
// Vary modal content when opened
const sendMessageModal = document.getElementById("example-modal-8");
if (sendMessageModal) {
sendMessageModal.addEventListener("show.bs.modal", (event) => {
// Button that triggered the modal
const button = event.relatedTarget;
// Extract info from data-bs-* attributes
const recipient = button.getAttribute("data-bs-recipient");
// If necessary, you could initiate an Ajax request here
// and then do the updating in a callback
// Update the modal's content
const modalTitle = sendMessageModal.querySelector(".modal-title");
const modalInput = sendMessageModal.querySelector(".modal-body input");
modalTitle.textContent = `New message to ${recipient}`;
modalInput.value = recipient;
});
}
Toggle between modals #
Toggle between multiple modals with some clever placement of the data-bs-target
and data-bs-toggle
attributes. For example, you could toggle a password reset modal from within an already open sign in modal. Please note multiple modals cannot be open at the same time—this method simply toggles between two separate modals.
Toggle between modals after opening the first one...
HTML
<!-- First modal toggle -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-9">
Launch modal
</button>
<!-- First modal -->
<div class="modal fade" id="example-modal-9" tabindex="-1" aria-labelledby="modal-title-9" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-9">First modal</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
This is the body of the first modal. You can toggle to the second modal by clicking the button below. Multiple modals cannot be open at the same time!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-10">Second modal</button>
</div>
</div>
</div>
</div>
<!-- Second modal -->
<div class="modal fade" id="example-modal-10" tabindex="-1" aria-labelledby="modal-title-10" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modal-title-10">Second modal</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
This is the body of the second modal. You can go back to the first modal by clicking the button below. Multiple modals cannot be open at the same time!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#example-modal-9">First modal</button>
</div>
</div>
</div>
</div>
Remove animation #
For modals that simply appear rather than fade in to view, remove the .fade
class from your modal markup.
Dynamic heights #
If the height of a modal changes while it is open, you should call myModal.handleUpdate()
to readjust the modal's position in case a scrollbar appears.
Optional sizes #
Modals have three optional sizes, available via modifier classes to be placed on a .modal-dialog
. These sizes kick in at certain breakpoints to avoid horizontal scrollbars on narrower viewports. Our default modal without modifier class constitutes the "medium" size modal.
Open modal with optional sizes...
HTML
<!-- Small modal -->
<div class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
...
</div>
</div>
</div>
<!-- Large modal -->
<div class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
...
</div>
</div>
</div>
<!-- Extra large modal -->
<div class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
...
</div>
</div>
</div>
Fullscreen modals #
Another override is the option to pop up a modal that covers the user viewport, available via modifier classes that are placed on a .modal-dialog
.
Open fullscreen modals (including responsive variation)...
HTML
<!-- Fullscreen modal -->
<div class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
...
</div>
</div>
</div>
<!-- Responsive fullscreen modal -->
<div class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-fullscreen-sm-down">
<div class="modal-content">
...
</div>
</div>
</div>
JavaScript usage #
halfmoon.js
Halfmoon is a drop-in replacement for Bootstrap. We implement no JavaScript on our own, therefore, there is no halfmoon.js
. Instead we rely entirely on bootstrap.bundle.js
(which can be downloaded from Bootstrap's website). Read the JavaScript section on our download page to learn more. It also contains a starter template to help you get started quickly.
The examples on this page use data-bs-*
attributes for functionality, which is usually enough to cover a majority of use-cases. You can read about options, methods, events, and more in the official Bootstrap documentation.
Modal - Bootstrap
Continue reading on the offical documentation website
Help us grow
Our main goal is to make Halfmoon the go-to framework for building websites, dashboards and tools. If you believe in our mission, consider becoming a sponsor and help us grow.
You can email us directly if you have any queries. We are always happy to answer.
Subscribe for updates
We will notify you when the framework gets a substantial update. No spam ever.
Follow us on Twitter so that you can stay updated that way.