Skip to content

Alert dialog

An alert dialog is a dialog recipe for confirmations — no new CSS or behavior. On the <dialog class="re-dialog"> add role="alertdialog", aria-labelledby (the title) and aria-describedby (the message), and put native autofocus on the safe action (Cancel) so the destructive button is never the default target. It’s driven by the existing enhanceDialog.

import { enhanceDialog } from "@relements/core/behaviors/dialog";
enhanceDialog(document);

For a critical choice, add data-re-dialog-no-dismiss to block Escape and backdrop dismissal so the user must pick an explicit action. A no-dismiss dialog must always contain a close control (the Cancel button) — otherwise it’s a keyboard trap; enhanceDialog warns in the console if one is missing. The recipe drops the corner × for exactly this reason.

Delete project?

This permanently deletes “Acme site” and all of its data. This action cannot be undone.

Live example
<button
  type="button"
  class="re-button"
  data-variant="danger"
  data-re-dialog-trigger
  data-re-dialog-target="confirm-delete"
>
  Delete project
</button>

<dialog
  class="re-dialog"
  id="confirm-delete"
  role="alertdialog"
  aria-labelledby="confirm-delete-title"
  aria-describedby="confirm-delete-desc"
  data-re-dialog-no-dismiss
>
  <header class="re-dialog__header">
    <h2 class="re-dialog__title" id="confirm-delete-title">Delete project?</h2>
  </header>
  <div class="re-dialog__body">
    <p id="confirm-delete-desc">
      This permanently deletes “Acme site” and all of its data. This action cannot be undone.
    </p>
  </div>
  <footer class="re-dialog__footer">
    <button
      type="button"
      class="re-button"
      data-variant="ghost"
      data-re-dialog-close
      value="cancel"
      autofocus
    >
      Cancel
    </button>
    <button
      type="button"
      class="re-button"
      data-variant="danger"
      data-re-dialog-close
      value="confirm"
    >
      Delete
    </button>
  </footer>
</dialog>

Without data-re-dialog-no-dismiss, an alertdialog still dismisses on Escape (and backdrop, with data-re-dialog-close-on-backdrop) — use this for non-critical alerts.

Session expiring

You’ll be signed out in 2 minutes. Escape or backdrop dismisses this one.

Live example
<button
  type="button"
  class="re-button"
  data-variant="secondary"
  data-re-dialog-trigger
  data-re-dialog-target="session-expiring"
>
  Show alert
</button>

<dialog
  class="re-dialog"
  id="session-expiring"
  role="alertdialog"
  aria-labelledby="session-expiring-title"
  aria-describedby="session-expiring-desc"
  data-re-dialog-close-on-backdrop
>
  <header class="re-dialog__header">
    <h2 class="re-dialog__title" id="session-expiring-title">Session expiring</h2>
  </header>
  <div class="re-dialog__body">
    <p id="session-expiring-desc">
      You’ll be signed out in 2 minutes. Escape or backdrop dismisses this one.
    </p>
  </div>
  <footer class="re-dialog__footer">
    <button type="button" class="re-button" data-re-dialog-close value="ok" autofocus>
      Stay signed in
    </button>
  </footer>
</dialog>
  • Keyboard — Tab/Shift+Tab cycle the action buttons inside the browser-owned focus trap; Enter or Space activate the focused button. Escape dismisses a dismissible alert; a data-re-dialog-no-dismiss alert blocks Escape (and backdrop), so the user must pick an explicit action — the Cancel button is the only way out, which is why a no-dismiss dialog must always contain one.
  • Focus — opening calls native showModal(), which traps focus and renders the background inert; closing returns focus to the trigger. The autofocus attribute lands the initial focus on the safe action (Cancel / Stay signed in) so the destructive button is never the default target. Buttons show a visible :focus-visible ring.
  • Semantics — the native <dialog> carries role="alertdialog"; aria-labelledby points at the title and aria-describedby at the message, so assistive tech announces both on open and treats the content as an interruption that needs a response.

See the dialog component for the underlying behavior and the accessibility guide for project-wide conventions.