
Micromodal.js is a dependency-free JavaScript modal library that creates accessible dialog windows with ARIA state management, focus trapping, overlay dismissal, and keyboard close behavior.
It helps you build modern and performant modal UI for confirmations, signup forms, alerts, onboarding steps, product notices, and dashboard panels.
Note that Micromodal.js does not ship any CSS styles. You control the modal layout, overlay, animation, spacing, and theme through CSS, while the script handles modal behavior and accessibility state.
Features:
- Toggle ARIA visibility state.
- Close dialogs on overlay clicks.
- Close dialogs with the Escape key.
- Trap keyboard focus inside dialogs.
- Restore focus after closing.
- Support nested dialog stacks.
- Accept custom trigger attributes.
Use Cases:
- Signup modals show a form over the current page.
- Confirmation dialogs protect destructive dashboard actions.
- Product detail popups keep users inside a listing page.
- Onboarding dialogs explain one step before interaction continues.
How to use it:
1. Install microModal. The library works through npm, Yarn, CDN scripts, or a direct browser download.
# Yarn $ yarn add micromodal # NPM $ npm install micromodal
<!-- jsDelivr CDN --> <script src="https://cdn.jsdelivr.net/npm/micromodal/dist/micromodal.min.js"></script> <!-- unpkg CDN --> <script src="https://unpkg.com/micromodal/dist/micromodal.min.js"></script>
2. Import the package as an ES module or CommonJS module.
// ES module import for bundlers.
import MicroModal from 'micromodal';
// CommonJS import for older build setups.
var MicroModal = require('micromodal');3. Place modal markup near the closing body tag when the overlay should cover the full viewport. The trigger value must match the modal ID.
<button data-micromodal-trigger="signup-dialog">
Open signup dialog
</button>
<div class="modal" id="signup-dialog" aria-hidden="true">
<div class="modal__overlay" tabindex="-1" data-micromodal-close>
<div
class="modal__container"
role="dialog"
aria-modal="true"
aria-labelledby="signup-dialog-title"
>
<header class="modal__header">
<h2 id="signup-dialog-title">Join the early access list</h2>
<!-- This element closes the modal. -->
<button
class="modal__close"
type="button"
aria-label="Close signup dialog"
data-micromodal-close
>
×
</button>
</header>
<div class="modal__content">
<label for="signup-email">Email address</label>
<input id="signup-email" type="email" autocomplete="email">
</div>
</div>
</div>
</div>4. Initialize MicroModal and done.
// Bind all elements that use the default trigger attribute. MicroModal.init();
5. Add your own CSS to the modal window. Micromodal.js adds the open class, but your stylesheet must define how the modal appears.
.modal {
display: none;
}
.modal.is-open {
display: block;
}6. All configuration options.
onShow(function): Runs when a modal opens. The function receives the modal element, the previously focused element, and the event or trigger context.onClose(function): Runs when a modal closes. The function receives the modal element, the previously focused element, and the event or trigger context.openTrigger(string): Sets the data attribute used to open modals. The default value isdata-micromodal-trigger.closeTrigger(string): Sets the data attribute used to close modals. The default value isdata-micromodal-close.openClass(string): Sets the class added to the modal when it opens. The default value isis-open.disableScroll(boolean): Locks body scrolling while a modal stays open. The default value isfalse.disableFocus(boolean): Turns off automatic focus on the first focusable element inside the modal. The default value isfalse.awaitOpenAnimation(boolean): Waits for the open animation to finish before focus moves inside the modal. The default value isfalse.awaitCloseAnimation(boolean): Waits for the close animation to finish before the open class leaves the modal. The default value isfalse.debugMode(boolean): Controls diagnostic warnings for missing IDs and trigger problems. The default value isfalse.
MicroModal.init({
// options here
});7. API methods.
// Bind modal triggers found through the configured open attribute.
MicroModal.init({
disableScroll: true
});
// Create and register a modal instance for an element or ID.
MicroModal.initModal('account-login-dialog', {
openClass: 'is-open'
});
// Update configuration for an existing modal instance.
MicroModal.config('account-login-dialog', {
disableFocus: false
});
// Open a modal by ID.
MicroModal.show('account-login-dialog');
// Open a modal by ID with configuration for this call.
MicroModal.show('account-login-dialog', {
onShow: function (modal) {
console.info(modal.id + ' opened');
}
});
// Close a specific modal by ID.
MicroModal.close('account-login-dialog');
// Close the topmost active modal when nested modals exist.
MicroModal.close();
// Close every active modal instance.
MicroModal.closeAll();
// Remove a registered modal instance and its trigger listeners.
MicroModal.removeModal('account-login-dialog');8. Callback functions.
MicroModal.init({
// Runs when a modal opens.
onShow: function (modal, trigger) {
console.log('Opened modal:', modal.id);
console.log('Previous focus or trigger:', trigger);
},
// Runs when a modal closes.
onClose: function (modal, trigger) {
console.log('Closed modal:', modal.id);
console.log('Returned focus target:', trigger);
}
});Alternatives:
- WCAG-Compliant Accessible Modal System in JavaScript
- Bootstrap Style Accessible Modal Window In Pure JavaScript
- Accessible Modal Dialog Component In Vanilla JavaScript
- Accessible Modal Dialog With CSS3 Animations
- Minimal Accessible Modal JavaScript Plugin
- 10 Best Free Modal Libraries For Vanilla JavaScript And CSS
Changelog:
v0.7.0 (06/03/2026)
- Added MicroModal.closeAll() to close all open modals at once
- Added MicroModal.initModal() to register a modal dynamically after init()
- Added MicroModal.removeModal() to unregister a modal and clean up its event listeners
- Added MicroModal.config() to reconfigure a modal after initialization
- Support for nested (layered) modals – Esc closes only the topmost
- Setting role=”alertdialog” on a modal now disables Esc to close
- keydown listeners are now scoped to each modal element instead of document
- Close trigger detection now uses closest() for reliable nested element handling
- show(id, config) reuses existing modal instances; config passed to show() persists on the modal
- Config passed to init() now applies to all subsequent show() calls
- Added touchAction: none to scroll lock for iOS momentum scroll
v0.6.2 (05/31/2026)
- Bugfixes
v0.6.1 (03/22/2025)
- Add ability to pass an element to Micromodal.close()
v0.5.2 (03/18/2025)
- Fixed bugs
v0.4.10 (11/28/2020)
- Fixed bugs
v0.4.9 (11/24/2020)
- Fixed bugs
v0.4.7 (11/23/2020)
- Fixed bugs
v0.4.6 (03/27/2020)
- Removed focus error when no focusable element exists in the modal
v0.4.5 (03/26/2020)
- Bugs fixed
v0.4.4 (03/26/2020)
- Added ability to customize open class name
v0.4.3 (03/25/2020)
- Finds a focusable element which is not the close button on modal open
- Handle events cleanup if modals are not closed properly
- The original trigger event is now passed to the onShow and onClose methods
- Bugs fixed
v0.4.2 (02/25/2020)
- Add dist files into the zip.
v0.4.1 (09/05/2018)
- FEATURE A flag to awaitOpenAnimation before focusing on element in modal.
- FEATURE Passing actual node as second argument to onShow.
- BUGFIX Fixed issue where active element was undefined.
- BUGFIX Fixed issue where an opened modal could not be closed by id.
v0.4.0 (05/06/2018)
- Added abilty to close modals by ID
- Fixed bug where micromodal would error on initialization
- Fixed bug where IE crashed due to null reference
- Fixed bug which didn’t lock modal overlay in IE
v0.3.2 (07/08/2018)
- BUGFIX Fixed bundling for es and umd builds







