npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fractaledmind/dialog-closedby-polyfill

v1.2.5

Published

Polyfill for the HTMLDialogElement closedBy attribute (fork with light-dismiss race condition fix)

Downloads

904

Readme

dialog-closedby-polyfill

A polyfill for the HTMLDialogElement closedby attribute, providing control over how dialogs can be dismissed.

Note: The HTML attribute is closedby (lowercase), while the JavaScript property is closedBy (camelCase).

Features

  • 🎯 Implements the closedby attribute for both modal and non-modal <dialog> elements
  • 🔒 Three closing modes: any, closerequest, and none
  • 🚀 Zero dependencies
  • 📦 TypeScript support included
  • 🌐 Works in all modern browsers with <dialog> support
  • ✨ Automatically detects native support

Installation

npm install @fractaledmind/dialog-closedby-polyfill

Usage

The polyfill is automatically applied when imported:

// ES Modules (auto-applies if needed)
import "@fractaledmind/dialog-closedby-polyfill";

// CommonJS (auto-applies if needed)
require("@fractaledmind/dialog-closedby-polyfill");

Manual Control

If you need more control over when the polyfill is applied:

import { apply, isSupported } from "@fractaledmind/dialog-closedby-polyfill";

if (!isSupported()) {
  apply();
}

Or include it via CDN:

<!-- Polyfill applied automatically -->
<script
  type="module"
  src="https://unpkg.com/@fractaledmind/dialog-closedby-polyfill"
></script>

<!-- polyfill manually -->
<script type="module">
  import {
    isSupported,
    apply,
  } from "https://unpkg.com/@fractaledmind/dialog-closedby-polyfill";
  if (!isSupported()) apply();
</script>

Demo

https://tak-dcxi.github.io/github-pages-demo/closedby.html

How it works

The closedby attribute controls how a dialog (modal or non-modal) can be dismissed:

Closing Behavior Matrix

| closedby value | ESC key | Backdrop click | close() method | | ---------------- | ------- | -------------- | ---------------- | | "any" | ✅ | ✅ | ✅ | | "closerequest" | ✅ | ❌ | ✅ | | "none" | ❌ | ❌ | ✅ |

closedby="any" (default)

The dialog can be closed by:

  • Pressing the ESC key
  • Clicking the backdrop
  • Calling the close() method
<dialog
  id="dialog-any"
  closedby="any"
  aria-labelledby="dialog-any-title"
  autofocus
>
  <h1 id="dialog-any-title">any</h1>
  <p>This dialog can be closed in any way</p>
  <button type="button" commandfor="dialog-any" command="close">Close</button>
</dialog>

closedby="closerequest"

The dialog can be closed by:

  • Pressing the ESC key
  • Calling the close() method
  • ❌ Clicking the backdrop (disabled)
<dialog
  id="dialog-closerequest"
  closedby="closerequest"
  aria-labelledby="dialog-closerequest-title"
  autofocus
>
  <h1 id="dialog-closerequest-title">closerequest</h1>
  <p>This dialog cannot be closed by clicking outside</p>
  <button type="button" commandfor="dialog-closerequest" command="close">
    Close
  </button>
</dialog>

closedby="none"

The dialog can only be closed by:

  • Calling the close() method
  • ❌ Pressing the ESC key (disabled)
  • ❌ Clicking the backdrop (disabled)
<dialog
  id="dialog-none"
  closedby="none"
  aria-labelledby="dialog-none-title"
  autofocus
>
  <h1 id="dialog-none-title">none</h1>
  <p>This dialog can only be closed programmatically</p>
  <button type="button" commandfor="dialog-none" command="close">Close</button>
</dialog>

JavaScript API

You can also set the attribute via JavaScript:

const dialog = document.querySelector("dialog");

// Using setAttribute
dialog.setAttribute("closedby", "none");

// Using the property (when polyfill is loaded)
dialog.closedBy = "closerequest";

Dynamic Changes

The closedby attribute can be changed while the dialog is open:

const dialog = document.querySelector("dialog");
dialog.showModal();

// Change behavior while dialog is open
setTimeout(() => {
  dialog.closedBy = "none"; // Now only closeable via close() method
}, 3000);

Browser Support

This polyfill works in all browsers that support the native <dialog> element.

Native closedby support:

  • Chrome 134+
  • Safari: Not implemented yet
  • Firefox: Not implemented yet
  • Edge: 134+

Dialog element support (required for polyfill):

  • Chrome 37+
  • Firefox 98+
  • Safari 15.4+
  • Edge 79+

Note: For browsers without native closedby support, this polyfill provides the functionality. For older browsers without <dialog> element support, you'll also need a dialog element polyfill.

API

Functions

isSupported(): boolean

Check if the browser natively supports the closedby attribute.

import { isSupported } from "@fractaledmind/dialog-closedby-polyfill";

if (isSupported()) {
  console.log("Native closedby support available!");
}

isPolyfilled(): boolean

Check if the polyfill has already been applied.

import { isPolyfilled } from "@fractaledmind/dialog-closedby-polyfill";

if (isPolyfilled()) {
  console.log("Polyfill has been applied");
}

apply(): void

Manually apply the polyfill. This is called automatically when importing the main module.

import { apply } from "@fractaledmind/dialog-closedby-polyfill";

apply(); // Apply the polyfill

TypeScript Support

TypeScript definitions are included. The polyfill extends the HTMLDialogElement interface:

interface HTMLDialogElement {
  closedBy: "any" | "closerequest" | "none";
}

Implementation Details

The polyfill works by:

  1. Extending HTMLDialogElement: Adds the closedby property to dialog elements
  2. Intercepting showModal() and show(): Sets up event listeners when a dialog is opened (modal or non-modal)
  3. Handling Events:
    • keydown event for ESC key detection
    • click event on the dialog for backdrop clicks
    • cancel event dispatch and prevention based on closedby value
  4. Observing Changes: Uses MutationObserver to watch for attribute changes
  5. Cleanup: Removes event listeners when dialog is closed

Differences from Native Implementation

This polyfill aims to match the native implementation as closely as possible. However, there might be minor differences in edge cases. Please report any discrepancies you find.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see the LICENSE file for details

Recommended Polyfills

Invokers Polyfill

Declarative command/commandfor attributes to provide dialog button operations with markup only.

<!-- Works seamlessly with this polyfill -->
<button type="button" commandfor="my-dialog" command="show-modal">
  Open Dialog
</button>
<dialog
  id="my-dialog"
  closedby="closerequest"
  aria-labelledby="my-dialog-heading"
  autofocus
>
  <h1 id="my-dialog-heading">Heading</h1>
  <p>Content</p>
  <button type="button" commandfor="my-dialog" command="close">Close</button>
</dialog>

Related Links

Acknowledgments

This polyfill is inspired by the native implementation and the work of the web standards community.