Dialog Polyfill provides a complete implementation of the HTML5 <dialog> element and <form method="dialog"> functionality for browsers that don't natively support it. It enables modal and non-modal dialogs with proper focus management, backdrop handling, and form integration while maintaining compatibility with modern browsers including IE9+.
npm install dialog-polyfillimport dialogPolyfill from 'dialog-polyfill';For CommonJS:
const dialogPolyfill = require('dialog-polyfill');For UMD (browser script):
<script src="node_modules/dialog-polyfill/dist/dialog-polyfill.js"></script>
<!-- dialogPolyfill is now available globally -->Important: The CSS file must also be included:
<link rel="stylesheet" type="text/css" href="node_modules/dialog-polyfill/dist/dialog-polyfill.css" />import dialogPolyfill from 'dialog-polyfill';
// Create a dialog element
const dialog = document.createElement('dialog');
dialog.innerHTML = `
<p>This is a dialog!</p>
<form method="dialog">
<button type="submit">Close</button>
</form>
`;
document.body.appendChild(dialog);
// Register the dialog with the polyfill
dialogPolyfill.registerDialog(dialog);
// Now the dialog can be used with native API
dialog.showModal(); // Shows as modal with backdrop
dialog.show(); // Shows as non-modal
dialog.close(); // Closes the dialogRegister dialog elements to enable polyfill functionality when native support is unavailable.
/**
* Registers a dialog element for polyfill functionality.
* Only applies polyfill if native support is not available.
* @param dialog - The dialog element to register
*/
function registerDialog(dialog: HTMLDialogElement): void;
/**
* Forces registration even when native support exists.
* Shows console warning when native support is detected.
* @param dialog - The dialog element to force register
*/
function forceRegisterDialog(dialog: HTMLDialogElement): void;Usage Examples:
// Standard registration (recommended)
const dialog = document.querySelector('dialog');
dialogPolyfill.registerDialog(dialog);
// Force registration for testing
dialogPolyfill.forceRegisterDialog(dialog);Methods added to registered dialog elements for showing and hiding dialogs.
/**
* Shows the dialog as non-modal (user can interact with page)
*/
show(): void;
/**
* Shows the dialog as modal with backdrop (blocks page interaction)
* @throws Error if dialog is already open or not in DOM
*/
showModal(): void;
/**
* Closes the dialog and optionally sets return value
* @param returnValue - Optional return value to set
* @throws Error if dialog is not open
*/
close(returnValue?: string): void;Usage Examples:
// Show as non-modal dialog
dialog.show();
console.log(dialog.open); // true
// Show as modal dialog with backdrop
dialog.showModal(); // Adds backdrop, traps focus
// Close with return value
dialog.close('cancelled');
console.log(dialog.returnValue); // 'cancelled'Properties available on registered dialog elements.
/**
* Boolean indicating if dialog is currently open
*/
open: boolean;
/**
* String value returned when dialog is closed via form submission
*/
returnValue: string;Enhanced form submission behavior for forms with method="dialog".
<!-- Form with method="dialog" closes containing dialog -->
<dialog>
<form method="dialog">
<button type="submit" value="ok">OK</button>
<button type="submit" value="cancel">Cancel</button>
</form>
</dialog>Behavior:
method="dialog" closes the containing dialogvalue becomes the dialog's returnValue<button>, <input type="submit">, and <input type="image">Usage Example:
dialog.addEventListener('close', function() {
console.log('Dialog closed with value:', dialog.returnValue);
});
// HTML form with method="dialog" will automatically close dialog
// and set returnValue to the clicked button's valueEvents fired by dialog elements during their lifecycle.
/**
* Fired when dialog is closed via close() method
* Event properties: bubbles: false, cancelable: false
*/
'close': Event;
/**
* Fired when Escape key is pressed in modal dialog
* Event properties: bubbles: false, cancelable: true
* If not prevented, closes the dialog
*/
'cancel': Event;Usage Examples:
// Listen for dialog close
dialog.addEventListener('close', function(event) {
console.log('Dialog was closed');
});
// Prevent dialog close on Escape key
dialog.addEventListener('cancel', function(event) {
event.preventDefault(); // Dialog stays open
});CSS classes and styles provided by the polyfill. The CSS file must be included for proper dialog functionality.
/* Base dialog element styles */
dialog {
position: absolute;
left: 0; right: 0;
width: fit-content;
height: fit-content;
margin: auto;
border: solid;
padding: 1em;
background: white;
color: black;
display: block;
}
/* Hide dialogs when not open */
dialog:not([open]) {
display: none;
}
/* Backdrop element inserted after modal dialogs */
dialog + .backdrop {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
background: rgba(0,0,0,0.1);
}
/* Helper class for fixed positioning */
dialog.fixed {
position: fixed;
top: 50%;
transform: translate(0, -50%);
}
/* Internal overlay for modal management (do not style directly) */
._dialog_overlay {
position: fixed;
top: 0; right: 0; bottom: 0; left: 0;
}CSS File Inclusion:
<link rel="stylesheet" type="text/css" href="node_modules/dialog-polyfill/dist/dialog-polyfill.css" />Usage Examples:
<!-- Apply fixed positioning helper class -->
<dialog class="fixed">
<p>This dialog will be centered regardless of scroll position</p>
</dialog>
<!-- Style the backdrop -->
<style>
dialog + .backdrop {
background: rgba(0,0,0,0.5);
}
</style>Utility methods exposed for advanced positioning and behavior control.
/**
* Repositions dialog to center it vertically in viewport
* @param element - Dialog element to reposition
*/
function reposition(element: HTMLDialogElement): void;
/**
* Determines if dialog needs automatic centering
* @param dialog - Dialog element to check
* @returns true if dialog should be auto-centered
*/
function needsCentering(dialog: HTMLDialogElement): boolean;
/**
* Checks if dialog positioning is set via CSS rules
* @param element - Dialog element to check
* @returns true if top/bottom positioning found in stylesheets
*/
function isInlinePositionSetByStylesheet(element: HTMLDialogElement): boolean;Internal dialog manager for handling modal dialog stacking and focus management. Exposed as a constructor for advanced use cases.
/**
* Constructor for the dialog manager system
* Creates a new dialog manager instance with modal stacking capabilities
*/
new DialogManager(): DialogManager;
interface DialogManager {
/** Array of currently stacked modal dialogs */
pendingDialogStack: Array<any>;
/** Overlay element for modal backdrop management */
overlay: HTMLElement;
/** Blocks document interaction when first modal is shown */
blockDocument(): void;
/** Restores document interaction when last modal is closed */
unblockDocument(): void;
/** Updates z-index stacking for all open dialogs */
updateStacking(): void;
/** Adds a dialog to the modal stack */
pushDialog(dialogInfo: any): boolean;
/** Removes a dialog from the modal stack */
removeDialog(dialogInfo: any): void;
}Properties available on the main dialogPolyfill object for advanced usage and form handling.
/**
* Global dialog manager instance
*/
dm: DialogManager;
/**
* Tracks the form submitter element for method="dialog" forms
* Used internally for form submission handling
*/
formSubmitter: HTMLElement | null;
/**
* Stores click coordinates for image input submissions
* Format: "x,y" coordinates for <input type="image"> elements
*/
imagemapUseValue: string | null;Modal Dialog Limitations:
Stacking Context Issues:
Dialogs should ideally be direct children of <body>. If this isn't possible, use the .fixed CSS class for proper positioning:
dialog.fixed {
position: fixed;
top: 50%;
transform: translate(0, -50%);
}Common errors thrown by dialog methods:
// showModal() errors
'Failed to execute \'showModal\' on dialog: The element is already open'
'Failed to execute \'showModal\' on dialog: The element is not in a Document'
'Failed to execute \'showModal\' on dialog: There are too many open modal dialogs'
// close() errors
'Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute'
// forceRegisterDialog() errors
'Failed to register dialog: The element is not a dialog'interface DialogManager {
pendingDialogStack: Array<any>;
overlay: HTMLElement;
blockDocument(): void;
unblockDocument(): void;
updateStacking(): void;
pushDialog(dialogInfo: any): boolean;
removeDialog(dialogInfo: any): void;
}
interface DialogPolyfillType {
registerDialog(dialog: HTMLDialogElement): void;
forceRegisterDialog(dialog: HTMLDialogElement): void;
reposition(element: HTMLDialogElement): void;
needsCentering(dialog: HTMLDialogElement): boolean;
isInlinePositionSetByStylesheet(element: HTMLDialogElement): boolean;
DialogManager: new () => DialogManager;
dm: DialogManager;
formSubmitter: HTMLElement | null;
imagemapUseValue: string | null;
}
// Enhanced HTMLDialogElement with polyfill methods
interface HTMLDialogElement extends HTMLElement {
open: boolean;
returnValue: string;
show(): void;
showModal(): void;
close(returnValue?: string): void;
}