HTML Dialog closedby Attribute

The HTML closedby attribute controls which user actions may close a <dialog> element. It lets you allow light dismiss, accept platform close requests such as the Escape key, or require a specific control inside the dialog.

This attribute makes dismissal behavior explicit in markup. It is useful for quick previews, confirmation steps, and important choices that should not disappear after an accidental outside click. Browser support is still limited in some widely used versions, so always provide a visible close or action button and test the required behavior.

Values of the closedby Attribute

Value Escape or platform close Click outside Provided close control
any Closes Closes Closes
closerequest Closes Does not close Closes
none Does not close automatically Does not close Closes

A developer-specified control includes a button that calls close() or a form submitted with method="dialog". The attribute controls user dismissal; it does not prevent your JavaScript from closing the dialog.

Default Dialog Behavior

When closedby is missing or invalid, the browser uses an automatic state. A dialog opened with showModal() behaves like closerequest. A non-modal dialog opened another way behaves like none.

Note: Use show() or showModal() to open a dialog. Manually adding the open attribute skips parts of the normal dialog opening behavior.

Allow Every Common Closing Method

Use closedby="any" for lightweight content that users should dismiss quickly. A modal dialog can then close through its button, a platform close request, or a click outside its bounds.

Example:

<button id="openPreview">Preview order</button>

<dialog id="preview" closedby="any">
  <h2>Order preview</h2>
  <p>Check the delivery address before continuing.</p>
  <form method="dialog">
    <!-- A visible button remains available for every user. -->
    <button autofocus>Close preview</button>
  </form>
</dialog>

<script>
  const preview = document.querySelector("#preview");
  // Open the dialog as a modal interaction.
  document.querySelector("#openPreview").addEventListener("click", () => {
    preview.showModal();
  });
</script>

Require an Explicit Action

Use closedby="none" when the user must choose an action supplied by the interface. This can suit a required acknowledgement, but do not trap users without a clear way to leave or finish the step.

Example:

<dialog id="policy" closedby="none">
  <h2>Review delivery policy</h2>
  <p>You must accept or return to the previous page.</p>
  <form method="dialog">
    <!-- Both outcomes are explicit developer-provided controls. -->
    <button value="back">Go back</button>
    <button value="accept" autofocus>Accept</button>
  </form>
</dialog>

Use closerequest for Standard Modal Behavior

The closerequest value accepts Escape or the platform's equivalent dismiss gesture, but it does not add outside-click dismissal. It is a suitable default for many modal forms because keyboard users can leave without searching for a button while accidental backdrop clicks do not discard work.

Example:

<dialog id="profile" closedby="closerequest">
  <h2>Edit profile</h2>
  <form method="dialog">
    <label>Display name <input name="displayName"></label>
    <!-- method="dialog" closes without sending an HTTP request. -->
    <button value="cancel">Cancel</button>
    <button value="save">Save</button>
  </form>
</dialog>

Respond to Close and Cancel Events

The cancel event occurs when the browser receives a close request, and you can prevent it when unsaved input needs confirmation. The close event occurs after the dialog closes and exposes the form button value through returnValue.

Example:

const profileDialog = document.querySelector("#profile");
let hasUnsavedChanges = true;

profileDialog.addEventListener("cancel", (event) => {
  // Keep the dialog open while important changes remain unsaved.
  if (hasUnsavedChanges) event.preventDefault();
});

profileDialog.addEventListener("close", () => {
  // Read the value of the button that submitted the dialog form.
  console.log(profileDialog.returnValue);
});

Try the closedby Values

Open each dialog and compare its close button, Escape-key, and outside-click behavior.

Example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dialog closedby Demo</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 760px; margin: 30px auto; padding: 0 16px; }
    .controls { display: flex; flex-wrap: wrap; gap: 10px; }
    button { padding: 9px 14px; }
    dialog { max-width: 420px; border: 0; border-radius: 12px; box-shadow: 0 10px 35px #0005; }
    dialog::backdrop { background: #0f172a99; }
    #status { margin-top: 18px; font-weight: bold; }
  </style>
</head>
<body>
  <h1>Choose a Dialog Closing Rule</h1>
  <div class="controls">
    <button data-target="anyDialog">Open any</button>
    <button data-target="requestDialog">Open closerequest</button>
    <button data-target="noneDialog">Open none</button>
  </div>
  <p id="status">No dialog is open.</p>

  <dialog id="anyDialog" closedby="any">
    <h2>Quick Preview</h2>
    <p>Close this dialog with the button, Escape, or a click outside.</p>
    <form method="dialog"><button autofocus>Close</button></form>
  </dialog>

  <dialog id="requestDialog" closedby="closerequest">
    <h2>Confirm Details</h2>
    <p>Close this dialog with the button or Escape.</p>
    <form method="dialog"><button autofocus>Close</button></form>
  </dialog>

  <dialog id="noneDialog" closedby="none">
    <h2>Required Choice</h2>
    <p>Only the provided button closes this dialog.</p>
    <form method="dialog"><button autofocus>Accept and close</button></form>
  </dialog>

  <script>
    const status = document.querySelector('#status');

    document.querySelectorAll('[data-target]').forEach((button) => {
      button.addEventListener('click', () => {
        // Open the dialog named by the button.
        const dialog = document.querySelector('#' + button.dataset.target);
        dialog.showModal();
        status.textContent = 'Opened: closedby="' + dialog.getAttribute('closedby') + '"';
      });
    });

    document.querySelectorAll('dialog').forEach((dialog) => {
      // Report every successful close action.
      dialog.addEventListener('close', () => {
        status.textContent = 'The dialog closed.';
      });
    });
  </script>
</body>
</html>

Accessibility and Compatibility

  • Give the dialog a clear heading and concise purpose.
  • Place keyboard focus on a sensible control, often with autofocus.
  • Provide a visible way to close, cancel, or complete the dialog.
  • Do not add tabindex to the <dialog> element itself.
  • Restore or verify focus after closing, especially in complex interfaces.
  • Test older browsers because they may ignore closedby and use their normal dialog behavior.

Conclusion

The closedby attribute lets you match dialog dismissal to the importance of the task. Use any for quick content, closerequest for standard modal behavior, and none only when an explicit choice is necessary. A clear close control, correct focus, and browser testing remain essential.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram