Dialog
A modern component built on the native <dialog> element with built-in accessibility and backdrop support that replaces the old Modal component.
How it works
The Dialog component leverages the browser's native <dialog> element, providing built-in accessibility features, focus management, and backdrop handling without the complexity of custom implementations.
Key features of the native dialog:
- Native modal behavior via
showModal()with automatic focus trapping - Built-in backdrop using the
::backdroppseudo-element - Escape key handling closes the dialog by default
- Accessibility with proper focus management and ARIA attributes
- Top layer rendering ensures the dialog appears above all other content
Native <dialog> elements support two methods: show() opens the dialog inline without a backdrop or focus trapping, while showModal() opens it as a true modal in the browser's top layer with a backdrop, focus trapping, and Escape key handling. Bootstrap's Dialog component uses showModal() to provide the expected modal experience.
The animation effect of this component is dependent on the prefers-reduced-motion media query. See the reduced motion section of our accessibility documentation.
Example
Toggle a dialog by clicking the button below. The dialog uses the native showModal() API for true modal behavior.
The markup for a dialog is straightforward:
<dialog class="dialog" id="exampleDialog">
<div class="dialog-header">
<h1 class="dialog-title">Dialog title</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="20" height="20" fill="none">
<path fill="currentcolor" d="M12 0a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm-.646 4.646a.5.5 0 0 0-.707 0L8 7.293 5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.647a.5.5 0 1 0 .708.707L8 8.707l2.647 2.646a.5.5 0 1 0 .707-.707L8.707 8l2.646-2.646a.5.5 0 0 0 0-.708z"/>
</svg>
</button>
</div>
<div class="dialog-body">
<p>Dialog body content goes here.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
<button type="button" class="btn btn-solid theme-primary">Save changes</button>
</div>
</dialog>
<button type="button" class="btn btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#exampleDialog">
Open dialog
</button>Static backdrop
When backdrop is set to static, the dialog will not close when clicking outside of it. Click the button below to try it.
Scrolling long content
When dialogs have content that exceeds the viewport height, the entire dialog scrolls within the viewport. The header, body, and footer all scroll together.
You can also create a scrollable dialog that scrolls the dialog body while keeping the header and footer fixed. Add .dialog-scrollable to the .dialog element.
<!-- Scrollable body dialog -->
<dialog class="dialog dialog-scrollable" id="scrollableBodyDialog">
<div class="dialog-header">
<h1 class="dialog-title">Scrollable body</h1>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="20" height="20" fill="none">
<path fill="currentcolor" d="M12 0a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4zm-.646 4.646a.5.5 0 0 0-.707 0L8 7.293 5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.647a.5.5 0 1 0 .708.707L8 8.707l2.647 2.646a.5.5 0 1 0 .707-.707L8.707 8l2.646-2.646a.5.5 0 0 0 0-.708z"/>
</svg>
</button>
</div>
<div class="dialog-body">
<!-- Long content here -->
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-solid theme-secondary" data-bs-dismiss="dialog">Close</button>
</div>
</dialog>For a dialog that extends beyond the viewport and scrolls as a whole, add .dialog-overflow and wrap the content in a .dialog-box element. The <dialog> becomes a full-viewport scrollable container, and the .dialog-box is the visual dialog that scrolls up and down.
<!-- Overflow dialog (entire dialog scrolls within viewport) -->
<dialog class="dialog dialog-overflow" id="overflowDialog">
<div class="dialog-box">
<div class="dialog-header">...</div>
<div class="dialog-body">
<!-- Very long content here -->
</div>
<div class="dialog-footer">...</div>
</div>
</dialog>Swapping dialogs
When a toggle trigger is inside an open dialog, clicking it will swap dialogs—opening the new one before closing the current. This ensures the backdrop stays visible throughout the transition with no flash.
The swap behavior is automatic when a data-bs-toggle="dialog" trigger is inside an already-open dialog:
<!-- First dialog -->
<dialog class="dialog" id="dialog1">
<div class="dialog-body">
<p>Click below to swap to dialog 2.</p>
</div>
<div class="dialog-footer">
<!-- This trigger is inside dialog1, so clicking it will swap -->
<button type="button" class="btn btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#dialog2">
Go to dialog 2
</button>
</div>
</dialog>
<!-- Second dialog -->
<dialog class="dialog" id="dialog2">
<div class="dialog-body">
<p>You're now in dialog 2.</p>
</div>
<div class="dialog-footer">
<button type="button" class="btn btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#dialog1">
Back to dialog 1
</button>
</div>
</dialog>Non-modal dialogs
By default, dialogs open as modals using the native showModal() method. You can also open dialogs as non-modal using show() by setting modal to false. Non-modal dialogs:
- Have no backdrop
- Don't trap focus
- Don't block interaction with the rest of the page
- Don't render in the browser's top layer
- Still respond to Escape key (if
keyboard: true)
<button type="button" class="btn btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#nonModalDialog" data-bs-modal="false">
Open non-modal dialog
</button> const dialog = new bootstrap.Dialog('#myDialog', { modal: false })
dialog.show()Optional sizes
Dialogs have three optional sizes, available via modifier classes to be placed on a .dialog. These sizes kick in at certain breakpoints to avoid horizontal scrollbars on narrower viewports.
| Size | Class | Dialog max-width |
|---|---|---|
| Small | .dialog-sm | 300px |
| Default | — | 500px |
| Large | .dialog-lg | 800px |
| Extra large | .dialog-xl | 1140px |
<dialog class="dialog dialog-xl">...</dialog>
<dialog class="dialog dialog-lg">...</dialog>
<dialog class="dialog dialog-sm">...</dialog>Fullscreen dialog
Use .dialog-fullscreen to make the dialog cover the entire viewport.
Responsive fullscreen variants are also available. These make the dialog fullscreen only below a specific breakpoint.
| Class | Fullscreen below |
|---|---|
.dialog-fullscreen | Always |
.dialog-fullscreen-sm-down | 576px |
.dialog-fullscreen-md-down | 768px |
.dialog-fullscreen-lg-down | 1024px |
.dialog-fullscreen-xl-down | 1280px |
.dialog-fullscreen-2xl-down | 1536px |
<dialog class="dialog dialog-fullscreen-lg-down">...</dialog>JavaScript behavior
Via data attributes
Toggle a dialog without writing JavaScript. Set data-bs-toggle="dialog" on a controller element, like a button, along with a data-bs-target="#foo" to target a specific dialog to toggle.
<button type="button" data-bs-toggle="dialog" data-bs-target="#myDialog">
Launch dialog
</button>Dismiss
Dismissal can be achieved with the data-bs-dismiss attribute on a button within the dialog:
<button type="button" data-bs-dismiss="dialog">Close</button>Via JavaScript
Create a dialog with a single line of JavaScript:
const myDialog = new bootstrap.Dialog('#myDialog')Options
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-bs-, as in data-bs-backdrop="static".
| Name | Type | Default | Description |
|---|---|---|---|
backdrop | boolean or 'static' | true | For modal dialogs, clicking the backdrop dismisses the dialog. Specify static for a backdrop which doesn't close the dialog when clicked. Has no effect on non-modal dialogs. |
keyboard | boolean | true | Closes the dialog when escape key is pressed. |
modal | boolean | true | When true, opens the dialog as a modal using showModal() with backdrop, focus trapping, and top layer rendering. When false, opens as a non-modal dialog using show() without backdrop or focus trapping. |
Methods
Passing options
Activates your content as a dialog. Accepts an optional options object.
const myDialog = new bootstrap.Dialog('#myDialog', {
keyboard: false
})| Method | Description |
|---|---|
show | Opens the dialog. Returns to the caller before the dialog has actually been shown (i.e. before the shown.bs.dialog event occurs). |
hide | Hides the dialog. Returns to the caller before the dialog has actually been hidden (i.e. before the hidden.bs.dialog event occurs). |
toggle | Toggles the dialog. Returns to the caller before the dialog has actually been shown or hidden (i.e. before the shown.bs.dialog or hidden.bs.dialog event occurs). |
handleUpdate | Provided for API consistency with Modal. Native dialogs handle their own positioning. |
dispose | Destroys an element's dialog. |
getInstance | Static method which allows you to get the dialog instance associated with a DOM element. |
getOrCreateInstance | Static method which allows you to get the dialog instance associated with a DOM element, or create a new one in case it wasn't initialized. |
Events
Bootstrap's dialog class exposes a few events for hooking into dialog functionality.
| Event | Description |
|---|---|
show.bs.dialog | Fires immediately when the show instance method is called. |
shown.bs.dialog | Fired when the dialog has been made visible to the user (will wait for CSS transitions to complete). |
hide.bs.dialog | Fires immediately when the hide instance method is called. |
hidden.bs.dialog | Fired when the dialog has finished being hidden from the user (will wait for CSS transitions to complete). |
hidePrevented.bs.dialog | Fired when the dialog is shown, its backdrop is static, and a click outside the dialog or an escape key press is performed (with keyboard set to false). |
cancel.bs.dialog | Fired when the user presses Escape and the dialog is about to close. |
const myDialog = document.getElementById('myDialog')
myDialog.addEventListener('hidden.bs.dialog', event => {
// do something...
})