or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-dialog-polyfill

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

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/dialog-polyfill@0.5.x

To install, run

npx @tessl/cli install tessl/npm-dialog-polyfill@0.5.0

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