CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dialog-polyfill

Polyfill for the HTML5 dialog element and form method='dialog' functionality with modal and non-modal support.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Dialog Polyfill

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+.

Package Information

  • Package Name: dialog-polyfill
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install dialog-polyfill

Core Imports

import 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" />

Basic Usage

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 dialog

Capabilities

Dialog Registration

Register 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);

Dialog Display Methods

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'

Dialog Properties

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;

Form Integration

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:

  • Form submission with method="dialog" closes the containing dialog
  • The submitter's value becomes the dialog's returnValue
  • Works with <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 value

Event Handling

Events 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 Styling Classes

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>

Advanced Utilities

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;

Dialog Manager

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;
}

Internal Properties

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;

Browser Support

  • Modern Browsers: Chrome, Firefox, Safari, Edge
  • Legacy Support: Internet Explorer 9+
  • Shadow DOM: Limited support (works but not recommended)

Limitations

Modal Dialog Limitations:

  • Should not be contained by parents that create stacking context
  • Browser chrome may not be accessible via tab key in some cases
  • CSS top/bottom changes while open are not retained

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%);
}

Error Handling

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'

Types

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;
}

Install with Tessl CLI

npx tessl i tessl/npm-dialog-polyfill

docs

index.md

tile.json