Accessibility pattern · Overlays

Alert dialog

An alert dialog is a modal dialog that interrupts on purpose, to get a decision about something that cannot be undone. Name it, say what will be lost in plain words, and put focus on the answer that loses nothing.

WCAG criteria
6
Keyboard rules
4
Checked with
axe, keyboard and the inspector

Live demo

Try it

Use it with a mouse, a keyboard or a screen reader. The inspector beside it shows what the browser tells assistive technology as you go: focus, state changes and announcements.

Danger zone

Delete this project

Removes Monsoon campaign and everything in it for the whole team.

Delete Monsoon campaign?

The project, its 48 files and its 3 shared links will be deleted for everyone on the team. This cannot be undone.

The demo works without JavaScript only as far as its HTML does; the inspector needs JavaScript.

Keyboard

Keys it answers to

Every action works without a pointer.

KeyWhat it does
Enter or SpaceOn Delete project, opens the alert dialog with focus on Cancel.
Tab or ShiftTabMoves between the dialog's controls only; the page behind cannot be reached.
EscapeCloses the dialog without deleting anything and returns focus to the trigger.
EnterIn the name field, confirms. If the name does not match, an error appears and focus stays in the field.

Screen readers

What it announces

Written from the roles, names and states in the markup.

WhenExpected announcement
The dialog opensDelete Monsoon campaign?, alert dialog. The project, its 48 files and its 3 shared links will be deleted for everyone on the team. This cannot be undone. Cancel, button
Tab reaches the destructive buttonDelete project, button
The typed name does not matchTo confirm, type monsoon-campaign, edit text, invalid entry. Type the project name exactly as shown.
The project is deletedProject deleted
The dialog is cancelledNothing was deleted

These are expected announcements, not recordings. Wording and order differ between screen readers and browsers.

Code

Copy the code

The exact files this demo runs on. The styles are served with a prefix that keeps this site's own styles out of the demo; what you copy is the original.

The markup

<div class="ap-alert-dialog" data-ap-alert-dialog>
  <div class="ap-alert-dialog__zone">
    <div class="ap-alert-dialog__copy">
      <p class="ap-alert-dialog__kicker">Danger zone</p>
      <h3 class="ap-alert-dialog__zone-name">Delete this project</h3>
      <p class="ap-alert-dialog__note">Removes Monsoon campaign and everything in it for the whole team.</p>
    </div>
    <button type="button" class="ap-btn ap-btn--danger" data-ap-open aria-haspopup="dialog">
      <svg class="ap-btn__icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M4 7h16"/><path d="M10 11v6M14 11v6"/><path d="m6 7 1 12a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2l1-12"/><path d="M9 7V4.5A1.5 1.5 0 0 1 10.5 3h3A1.5 1.5 0 0 1 15 4.5V7"/></svg>
      Delete project
    </button>
  </div>
  <p class="ap-alert-dialog__status" role="status"></p>

  <dialog class="ap-alert-dialog__dialog" role="alertdialog" aria-labelledby="alert-dialog-name" aria-describedby="alert-dialog-desc">
    <form class="ap-alert-dialog__form" method="dialog">
      <span class="ap-alert-dialog__icon" aria-hidden="true">
        <svg viewBox="0 0 24 24" focusable="false"><path d="M10.3 3.9 2.4 17.6A2 2 0 0 0 4.1 20.6h15.8a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/><path d="M12 9.5v4.5"/><path d="M12 17.3h.01"/></svg>
      </span>
      <h2 class="ap-alert-dialog__name" id="alert-dialog-name">Delete Monsoon campaign?</h2>
      <p class="ap-alert-dialog__desc" id="alert-dialog-desc">The project, its 48 files and its 3 shared links will be deleted for everyone on the team. This cannot be undone.</p>
      <div class="ap-field ap-alert-dialog__confirm" data-ap-confirm hidden>
        <label class="ap-label" for="alert-dialog-confirm">To confirm, type <code>monsoon-campaign</code></label>
        <input class="ap-input" id="alert-dialog-confirm" name="confirm" data-ap-expect="monsoon-campaign" autocomplete="off" autocapitalize="off" spellcheck="false" aria-describedby="alert-dialog-error" />
        <p class="ap-error" id="alert-dialog-error" data-ap-error hidden>
          <svg class="ap-alert-dialog__err" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"/><path d="M12 7.5v5"/><path d="M12 16.2h.01"/></svg>
          Type the project name exactly as shown.
        </p>
      </div>
      <div class="ap-alert-dialog__actions">
        <button type="button" class="ap-btn" data-ap-cancel autofocus>Cancel</button>
        <button type="submit" class="ap-btn ap-btn--danger" value="delete">Delete project</button>
      </div>
    </form>
  </dialog>
</div>

WCAG 2.2

What it meets

The success criteria this pattern takes care of, and how.

  • 1.3.1 Info and Relationships Level A

    The dialog is named by its heading and described by the paragraph that states the cost, so both are read out when it opens.

  • 2.4.3 Focus Order Level A

    Focus starts on Cancel, the answer that loses nothing, and goes back to the trigger when the dialog closes.

  • 3.3.1 Error Identification Level A

    A name that does not match is reported in text beside the field, with aria-invalid, not just a red border.

  • 3.3.4 Error Prevention (Legal, Financial, Data) Level AA

    Deleting data waits for an explicit confirmation, and the high-stakes version asks for the project's name as well.

  • 4.1.2 Name, Role, Value Level A

    role=alertdialog tells assistive technology this is an urgent question, and the dialog element keeps the page behind inert.

  • 4.1.3 Status Messages Level AA

    The outcome, deleted or not, is written to a status line that is announced without moving focus.

Usage

When to use it

Use it

  • Confirming an action that destroys data or cannot be reversed, like deleting a project or closing an account.
  • A problem that blocks the task until someone decides, like leaving a page with unsaved work.

Use something else

  • Actions that can be undone: do them straight away and offer Undo instead.
  • News that needs no decision: use a status message or a toast.
  • Confirming routine actions: people learn to press the button without reading, which defeats the point.

Common failures

How it usually goes wrong

  • Focus on the destructive button

    Someone who presses Enter out of habit as the dialog appears deletes the project. Focus starts on Cancel here, so a reflex loses nothing.

  • A vague question

    "Are you sure?" with OK and Cancel says nothing about what happens. The heading names the project, the description says what is lost, and the button says Delete project.

  • No description

    Without aria-describedby only the heading is announced when the dialog opens, and the consequence is heard only by someone who goes looking for it.

  • Closing on a stray click

    A click outside the dialog is not an answer. This one closes only from its two buttons or Escape, and Escape always means cancel.

  • A greyed-out button with no reason

    A disabled Delete button gives no hint of what it is waiting for, and many screen readers skip it. Here the button always works and says what is wrong.

  • role=alert instead of a dialog

    role=alert reads a message out once, but nothing takes focus to its buttons or keeps the page behind out of reach. The alert dialog does both.

Notes

Building it

  • role=alertdialog on a dialog element replaces its role but keeps everything showModal() gives: the top layer, the inert page and Escape.
  • The autofocus attribute puts focus on Cancel. With the name check on, the script moves focus into the field instead, because typing deletes nothing.
  • Label the destructive button with the action, "Delete project", not "OK" or "Yes", so it still makes sense to someone who tabs straight to it.
  • Leave light dismiss off: a decision this size needs an explicit answer, and the status line confirms which one was given.

Sources: WAI-ARIA Authoring Practices: Alert and Message Dialogs · WAI-ARIA 1.2: the alertdialog role

Checked with axe in light and dark themes, at desktop and phone widths, and by keyboard. Not yet tested with every screen reader and browser pair. Report a correction