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);Destructive confirmation
Section titled “Destructive confirmation”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.
<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> Dismissible alert
Section titled “Dismissible alert”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.
<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> Accessibility
Section titled “Accessibility”- 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-dismissalert 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. Theautofocusattribute 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-visiblering. - Semantics — the native
<dialog>carriesrole="alertdialog";aria-labelledbypoints at the title andaria-describedbyat 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.