Alert Dialog
A modal dialog that interrupts with an important question, such as confirming a deletion, and expects an answer.
- v1.0.0
- WAI-ARIA: Dialog (Modal)
- SSR
- Zoneless
- 4.1 kB gzip
- +9.7 kB Angular CDK, shared
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-dialogpnpm dlx @ndop/cli add alert-dialogyarn dlx @ndop/cli add alert-dialogbunx @ndop/cli add alert-dialogInstall the dependencies
npm install @ndop/primitives @ndop/corepnpm add @ndop/primitives @ndop/coreyarn add @ndop/primitives @ndop/corebun add @ndop/primitives @ndop/coreCopy the code into your project
At the paths your
ndop.jsonaliases point to; these use the defaults.src/app/ui/alert-dialog/alert-dialog.tsimport { computed, Directive, input } from '@angular/core'; import { NdDialog } from '@ndop/primitives/dialog'; import { NdAlertDialog, NdAlertDialogAction, NdAlertDialogCancel, NdAlertDialogContent, NdAlertDialogDescription, NdAlertDialogOverlay, NdAlertDialogPortal, NdAlertDialogTitle, NdAlertDialogTrigger, } from '@ndop/primitives/alert-dialog'; import { buttonVariants, type ButtonSize, type ButtonVariant, } from '@/ui/button/button'; import { cn } from '@/lib/utils'; /** * 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. * * @example * ```html * <ng-container ndAlertDialog>…</ng-container> * ``` */ @Directive({ selector: '[ndAlertDialog]', hostDirectives: [ { directive: NdDialog, inputs: ['open', 'defaultOpen'], outputs: ['openChange'], }, ], }) export class AlertDialog {} /** * The button that opens its alert dialog. * * @example * ```html * <button ndButton variant="destructive" ndAlertDialogTrigger>Delete</button> * ``` */ @Directive({ selector: '[ndAlertDialogTrigger]', hostDirectives: [NdAlertDialogTrigger], host: { 'data-slot': 'alert-dialog-trigger' }, }) export class AlertDialogTrigger {} /** * Marks the `ng-template` its alert dialog renders while open. * * @example * ```html * <ng-template ndAlertDialogPortal>…</ng-template> * ``` */ @Directive({ selector: 'ng-template[ndAlertDialogPortal]', hostDirectives: [NdAlertDialogPortal], }) export class AlertDialogPortal {} /** * The dimmed backdrop behind an alert dialog. Clicking it does nothing: * the user must answer. * * @example * ```html * <div ndAlertDialogOverlay></div> * ``` */ @Directive({ selector: '[ndAlertDialogOverlay]', hostDirectives: [NdAlertDialogOverlay], host: { 'data-slot': 'alert-dialog-overlay', '[class]': 'classes()' }, }) export class AlertDialogOverlay { /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( 'fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0', this.class(), ), ); } /** * 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. * * @example * ```html * <div ndAlertDialogContent> * <div ndAlertDialogHeader> * <h2 ndAlertDialogTitle>Delete this project?</h2> * <p ndAlertDialogDescription>This can't be undone.</p> * </div> * <div ndAlertDialogFooter> * <button ndAlertDialogCancel>Cancel</button> * <button ndAlertDialogAction variant="destructive">Delete</button> * </div> * </div> * ``` */ @Directive({ selector: '[ndAlertDialogContent]', hostDirectives: [NdAlertDialogContent], host: { 'data-slot': 'alert-dialog-content', '[attr.data-size]': 'size()', '[class]': 'classes()', }, }) export class AlertDialogContent { /** `default`, or `sm` for a compact, centered dialog. */ readonly size = input<'default' | 'sm'>('default'); /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( 'group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=default]:sm:max-w-lg', this.class(), ), ); } /** * Lays out an alert dialog's media, title and description. * * @example * ```html * <div ndAlertDialogHeader>…</div> * ``` */ @Directive({ selector: '[ndAlertDialogHeader]', host: { 'data-slot': 'alert-dialog-header', '[class]': 'classes()' }, }) export class AlertDialogHeader { /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( 'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-start sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]', this.class(), ), ); } /** * Lays out an alert dialog's buttons: stacked on small screens, in a row * at the end side otherwise. * * @example * ```html * <div ndAlertDialogFooter>…</div> * ``` */ @Directive({ selector: '[ndAlertDialogFooter]', host: { 'data-slot': 'alert-dialog-footer', '[class]': 'classes()' }, }) export class AlertDialogFooter { /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( 'flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end', this.class(), ), ); } /** * The question an alert dialog asks; it labels the dialog. * * @example * ```html * <h2 ndAlertDialogTitle>Delete this project?</h2> * ``` */ @Directive({ selector: '[ndAlertDialogTitle]', hostDirectives: [NdAlertDialogTitle], host: { 'data-slot': 'alert-dialog-title', '[class]': 'classes()' }, }) export class AlertDialogTitle { /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( 'text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2', this.class(), ), ); } /** * What answering means; it describes the dialog. * * @example * ```html * <p ndAlertDialogDescription>This can't be undone.</p> * ``` */ @Directive({ selector: '[ndAlertDialogDescription]', hostDirectives: [NdAlertDialogDescription], host: { 'data-slot': 'alert-dialog-description', '[class]': 'classes()' }, }) export class AlertDialogDescription { /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn('text-sm text-muted-foreground', this.class()), ); } /** * An icon above or beside the title, hidden from assistive technology. * * @example * ```html * <div ndAlertDialogMedia><svg ndIcon="circle-alert"></svg></div> * ``` */ @Directive({ selector: '[ndAlertDialogMedia]', host: { 'data-slot': 'alert-dialog-media', 'aria-hidden': 'true', '[class]': 'classes()', }, }) export class AlertDialogMedia { /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( "mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8", this.class(), ), ); } /** * The button that confirms, styled as a Button: its `(click)` runs, then * the dialog closes. Use `variant="destructive"` for destructive actions. * * @example * ```html * <button ndAlertDialogAction (click)="delete()">Delete</button> * ``` */ @Directive({ selector: 'button[ndAlertDialogAction]', hostDirectives: [NdAlertDialogAction], host: { 'data-slot': 'alert-dialog-action', '[class]': 'classes()', }, }) export class AlertDialogAction { /** Button style. */ readonly variant = input<ButtonVariant>('default'); /** Button size. */ readonly size = input<ButtonSize>('default'); /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( buttonVariants({ variant: this.variant(), size: this.size() }), this.class(), ), ); } /** * The button that cancels and closes, styled as an outline Button; focus * starts here. * * @example * ```html * <button ndAlertDialogCancel>Cancel</button> * ``` */ @Directive({ selector: 'button[ndAlertDialogCancel]', hostDirectives: [NdAlertDialogCancel], host: { 'data-slot': 'alert-dialog-cancel', '[class]': 'classes()', }, }) export class AlertDialogCancel { /** Button style. */ readonly variant = input<ButtonVariant>('outline'); /** Button size. */ readonly size = input<ButtonSize>('default'); /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( buttonVariants({ variant: this.variant(), size: this.size() }), this.class(), ), ); }src/app/lib/utils.ts/** * Class helpers used by every styled item. They come from `@ndop/core`; * this file is yours, so it is the place to customize them, for example by * wrapping `cn` with an extended tailwind-merge configuration for your own * utilities. * * @packageDocumentation */ export { cn, variants, type ClassValue, type VariantOf } from '@ndop/core';src/app/ui/button/button.tsimport { computed, Directive, input } from '@angular/core'; import { NdButton } from '@ndop/primitives/button'; import { cn, variants, type VariantOf } from '@/lib/utils'; /** * Class table for {@link Button}; also usable to style other elements like * a button. */ export const buttonVariants = variants({ base: "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-disabled:pointer-events-none data-disabled:opacity-50", variants: { variant: { default: 'bg-primary text-primary-foreground hover:bg-primary/90', destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40', outline: 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50', secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', link: 'text-primary underline-offset-4 hover:underline', }, size: { default: 'h-9 px-4 py-2 has-[>svg]:px-3', xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3", sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5', lg: 'h-10 rounded-md px-6 has-[>svg]:px-4', icon: 'size-9', 'icon-xs': "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3", 'icon-sm': 'size-8', 'icon-lg': 'size-10', }, }, defaults: { variant: 'default', size: 'default' }, }); /** Visual style of a {@link Button}. */ export type ButtonVariant = VariantOf<typeof buttonVariants, 'variant'>; /** Size of a {@link Button}. */ export type ButtonSize = VariantOf<typeof buttonVariants, 'size'>; /** * Styled button for a native `button` or an `a`, with the * `@ndop/primitives/button` behavior (safe default type, disabled links). * * @example * ```html * <button ndButton variant="outline" size="sm">Cancel</button> * <a ndButton variant="link" href="/docs">Docs</a> * ``` */ @Directive({ selector: 'button[ndButton], a[ndButton]', hostDirectives: [{ directive: NdButton, inputs: ['disabled'] }], host: { 'data-slot': 'button', '[attr.data-variant]': 'variant()', '[attr.data-size]': 'size()', '[class]': 'classes()', }, }) export class Button { /** Visual style. */ readonly variant = input<ButtonVariant>('default'); /** Height, padding and icon size. */ readonly size = input<ButtonSize>('default'); /** Extra classes, merged last so they win. */ readonly class = input(''); protected readonly classes = computed(() => cn( buttonVariants({ variant: this.variant(), size: this.size() }), this.class(), ), ); }Update the import paths to match your project
The files import each other through the
@/uiand@/libaliases.
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 |
|---|---|
| Tab | Moves focus to the next focusable element inside the dialog; from the last one, wraps to the first. |
| ShiftTab | Moves focus to the previous focusable element inside the dialog; from the first one, wraps to the last. |
| Escape | Closes the dialog, unless closeOnEscape is false. |
| Tab | Moves focus to the next focusable element inside; wraps from last to first. |
| ShiftTab | Moves focus to the previous focusable element inside; wraps from first to last. |
| Escape | Closes 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. | boolean | false |
[(open)]Whether the dialog is open. Two-way bindable with [(open)]. | boolean | false |
AlertDialogTrigger
[ndAlertDialogTrigger]The button that opens its alert dialog.
Manages aria-haspopup, aria-expanded, aria-controls.
| Data attribute | Values |
|---|---|
data-slot | alert-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-slot | alert-dialog-overlay |
data-state | — |
AlertDialogContent
[ndAlertDialogContent]role alertdialogThe 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-slot | alert-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-slot | alert-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-slot | alert-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-slot | alert-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-slot | alert-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-slot | alert-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-slot | alert-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-slot | alert-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.