Skip to content
Ndop UI

Alert Dialog

A modal dialog that interrupts with an important question, such as confirming a deletion, and expects an answer.

import { Component } from '@angular/core';
import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogOverlay,
  AlertDialogTitle,
  AlertDialog,
  AlertDialogPortal,
  AlertDialogTrigger,
} from '@/ui/alert-dialog/alert-dialog';
import { Button } from '@/ui/button/button';

/** A confirmation before signing out, with Cancel focused first. */
@Component({
  selector: 'example-alert-dialog-demo',
  imports: [
    AlertDialogAction,
    AlertDialogCancel,
    AlertDialogContent,
    AlertDialogDescription,
    AlertDialogFooter,
    AlertDialogHeader,
    AlertDialogOverlay,
    AlertDialogTitle,
    Button,
    AlertDialog,
    AlertDialogPortal,
    AlertDialogTrigger,
  ],
  template: `
    <ng-container ndAlertDialog>
      <button ndButton variant="outline" ndAlertDialogTrigger>Sign out</button>
      <ng-template ndAlertDialogPortal>
        <div ndAlertDialogOverlay></div>
        <div ndAlertDialogContent>
          <div ndAlertDialogHeader>
            <h2 ndAlertDialogTitle>Sign out of every device?</h2>
            <p ndAlertDialogDescription>
              You'll need to sign in again on your phone and other computers.
            </p>
          </div>
          <div ndAlertDialogFooter>
            <button ndAlertDialogCancel>Cancel</button>
            <button ndAlertDialogAction>Sign out</button>
          </div>
        </div>
      </ng-template>
    </ng-container>
  `,
})
export class AlertDialogDemoExample {}

An alert dialog interrupts with a question the user must answer before going on, such as confirming a deletion. It's announced as an alert dialog, labelled by its question and described by what answering means. Clicking outside doesn't close it; Escape and Cancel do, and focus starts on Cancel, the safe choice. Use size="sm" for a short, centered question with buttons side by side.

Installation

npx @ndop/cli add alert-dialog

Usage

import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogOverlay,
  AlertDialogTitle,
  AlertDialog,
  AlertDialogPortal,
  AlertDialogTrigger,
} from '@/ui/alert-dialog/alert-dialog';
import { Button } from '@/ui/button/button';
<ng-container ndAlertDialog>
  <button ndButton variant="outline" ndAlertDialogTrigger>Sign out</button>
  <ng-template ndAlertDialogPortal>
    <div ndAlertDialogOverlay></div>
    <div ndAlertDialogContent>
      <div ndAlertDialogHeader>
        <h2 ndAlertDialogTitle>Sign out of every device?</h2>
        <p ndAlertDialogDescription>
          You'll need to sign in again on your phone and other computers.
        </p>
      </div>
      <div ndAlertDialogFooter>
        <button ndAlertDialogCancel>Cancel</button>
        <button ndAlertDialogAction>Sign out</button>
      </div>
    </div>
  </ng-template>
</ng-container>

Examples

Alert Dialog destructive

Deleting a project, with an icon and a destructive action that runs before the dialog closes.

import { Component, signal } from '@angular/core';
import { NdIcon } from '@ndop/core';
import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogMedia,
  AlertDialogOverlay,
  AlertDialogTitle,
  AlertDialog,
  AlertDialogPortal,
  AlertDialogTrigger,
} from '@/ui/alert-dialog/alert-dialog';
import { Button } from '@/ui/button/button';

/**
 * Deleting a project: an icon, a destructive action whose handler runs
 * before the dialog closes, and the result reported on the page.
 */
@Component({
  selector: 'example-alert-dialog-destructive',
  imports: [
    AlertDialogAction,
    AlertDialogCancel,
    AlertDialogContent,
    AlertDialogDescription,
    AlertDialogFooter,
    AlertDialogHeader,
    AlertDialogMedia,
    AlertDialogOverlay,
    AlertDialogTitle,
    Button,
    AlertDialog,
    AlertDialogPortal,
    AlertDialogTrigger,
    NdIcon,
  ],
  template: `
    <div class="flex flex-col items-start gap-3">
      <ng-container ndAlertDialog>
        <button ndButton variant="destructive" ndAlertDialogTrigger>
          Delete project
        </button>
        <ng-template ndAlertDialogPortal>
          <div ndAlertDialogOverlay></div>
          <div ndAlertDialogContent>
            <div ndAlertDialogHeader>
              <div ndAlertDialogMedia><svg ndIcon="circle-alert"></svg></div>
              <h2 ndAlertDialogTitle>Delete "Website redesign"?</h2>
              <p ndAlertDialogDescription>
                Its 24 tasks and their comments are deleted for everyone. This
                can't be undone.
              </p>
            </div>
            <div ndAlertDialogFooter>
              <button ndAlertDialogCancel>Keep project</button>
              <button
                ndAlertDialogAction
                variant="destructive"
                (click)="deleted.set(true)"
              >
                Delete project
              </button>
            </div>
          </div>
        </ng-template>
      </ng-container>
      <p class="text-sm text-muted-foreground" aria-live="polite">
        @if (deleted()) {
          Project deleted.
        }
      </p>
    </div>
  `,
})
export class AlertDialogDestructiveExample {
  protected readonly deleted = signal(false);
}

Alert Dialog small

The small size: a short question with side-by-side buttons.

import { Component } from '@angular/core';
import {
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogOverlay,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialog,
  AlertDialogPortal,
  AlertDialogTrigger,
} from '@/ui/alert-dialog/alert-dialog';
import { Button } from '@/ui/button/button';

/** The small size: a short question with side-by-side buttons. */
@Component({
  selector: 'example-alert-dialog-small',
  imports: [
    AlertDialogAction,
    AlertDialogCancel,
    AlertDialogContent,
    AlertDialogDescription,
    AlertDialogFooter,
    AlertDialogHeader,
    AlertDialogOverlay,
    AlertDialogTitle,
    Button,
    AlertDialog,
    AlertDialogPortal,
    AlertDialogTrigger,
  ],
  template: `
    <ng-container ndAlertDialog>
      <button ndButton variant="outline" ndAlertDialogTrigger>
        Discard draft
      </button>
      <ng-template ndAlertDialogPortal>
        <div ndAlertDialogOverlay></div>
        <div ndAlertDialogContent size="sm">
          <div ndAlertDialogHeader>
            <h2 ndAlertDialogTitle>Discard draft?</h2>
            <p ndAlertDialogDescription>Your changes will be lost.</p>
          </div>
          <div ndAlertDialogFooter>
            <button ndAlertDialogCancel>Cancel</button>
            <button ndAlertDialogAction>Discard</button>
          </div>
        </div>
      </ng-template>
    </ng-container>
  `,
})
export class AlertDialogSmallExample {}

Accessibility

Implements the Dialog (Modal) pattern of the WAI-ARIA Authoring Practices.

Keyboard

Keys the component handles.

Key Action
TabMoves focus to the next focusable element inside the dialog; from the last one, wraps to the first.
ShiftTabMoves focus to the previous focusable element inside the dialog; from the first one, wraps to the last.
EscapeCloses the dialog, unless closeOnEscape is false.
TabMoves focus to the next focusable element inside; wraps from last to first.
ShiftTabMoves focus to the previous focusable element inside; wraps from first to last.
EscapeCloses the dialog, as Cancel does.

Focus

  • On open: focus moves to the first focusable element in the content, or to the content element itself when it has none.
  • While open: focus is trapped in the content.
  • On close: focus returns to the element that had it before opening, usually the trigger.
  • On open: focus moves to AlertDialogCancel.
  • While open: focus is trapped in the content.
  • On close: focus returns to the element that had it before opening, usually the trigger.

Right-to-left

Nothing mirrors: the dialog is centered, and Tab order follows the DOM. Nothing mirrors.

API reference

AlertDialog

[ndAlertDialog]

An alert dialog (@ndop/primitives/alert-dialog): a modal question the user must answer. Clicking outside doesn't close it; Escape and Cancel do. Put it on an ng-container; open is two-way bindable.

AlertDialog binding Type Default
[defaultOpen]
Initial open state when open is not bound.
booleanfalse
[(open)]
Whether the dialog is open. Two-way bindable with [(open)].
booleanfalse

AlertDialogTrigger

[ndAlertDialogTrigger]

The button that opens its alert dialog.

Manages aria-haspopup, aria-expanded, aria-controls.

Data attribute Values
data-slotalert-dialog-trigger
data-state —

AlertDialogPortal

ng-template[ndAlertDialogPortal]

Marks the ng-template its alert dialog renders while open.

AlertDialogOverlay

[ndAlertDialogOverlay]

The dimmed backdrop behind an alert dialog. Clicking it does nothing: the user must answer.

Manages aria-hidden.

AlertDialogOverlay binding Type Default
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-overlay
data-state —

AlertDialogContent

[ndAlertDialogContent]role alertdialog

The alert dialog box (@ndop/primitives/alert-dialog): an alertdialog labelled by its title, with focus starting on Cancel. size="sm" is a compact, centered layout with side-by-side buttons.

Manages aria-modal, aria-labelledby, aria-describedby.

AlertDialogContent binding Type Default
[size]
default, or sm for a compact, centered dialog.
'default' | 'sm''default'
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-content
data-size —
data-state —

AlertDialogHeader

[ndAlertDialogHeader]

Lays out an alert dialog's media, title and description.

AlertDialogHeader binding Type Default
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-header

AlertDialogFooter

[ndAlertDialogFooter]

Lays out an alert dialog's buttons: stacked on small screens, in a row at the end side otherwise.

AlertDialogFooter binding Type Default
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-footer

AlertDialogTitle

[ndAlertDialogTitle]

The question an alert dialog asks; it labels the dialog.

AlertDialogTitle binding Type Default
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-title

AlertDialogDescription

[ndAlertDialogDescription]

What answering means; it describes the dialog.

AlertDialogDescription binding Type Default
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-description

AlertDialogMedia

[ndAlertDialogMedia]

An icon above or beside the title, hidden from assistive technology.

AlertDialogMedia binding Type Default
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-media

AlertDialogAction

button[ndAlertDialogAction]

The button that confirms, styled as a Button: its (click) runs, then the dialog closes. Use variant="destructive" for destructive actions.

AlertDialogAction binding Type Default
[variant]
Button style.
'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link''default'
[size]
Button size.
'default' | 'xs' | 'sm' | 'lg' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg''default'
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-action

AlertDialogCancel

button[ndAlertDialogCancel]

The button that cancels and closes, styled as an outline Button; focus starts here.

AlertDialogCancel binding Type Default
[variant]
Button style.
'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link''outline'
[size]
Button size.
'default' | 'xs' | 'sm' | 'lg' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg''default'
[class]
Extra classes, merged last so they win.
string''
Data attribute Values
data-slotalert-dialog-cancel

Agent notes

Do

  • Ask a question with a clear answer, and name the buttons after what they do, such as "Delete project" rather than "OK".
  • Use the destructive variant for the action when it destroys something.
  • Say what can't be undone.

Don't

  • Don't use it for information that needs no answer; use a Toast or an Alert.
  • Don't put forms in it; use a Dialog.