Skip to content

Alert dialog <l-alert-dialog>

An interruptive confirmation dialog built on <l-dialog>. It renders its own cancel/confirm actions, exposes role="alertdialog", and closes when the user picks an action — unless you cancel the event. Use it to confirm a consequential action, not for generic content.

HTML tag<l-alert-dialog>
Native
Progressive
Plain
Shadow-DOM
Shadow-DOM Custom Element

Options

Basic

Open with command="--show" on a trigger button. The cancel and confirm actions are rendered for you; label them with cancel-text and confirm-text. The dialog closes automatically when an action is picked.

Once published, “Spring collection 2026” becomes visible to everyone on your storefront. You can still edit it afterwards.
Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="confirm-publish"
>
  Publish article
</button>

<l-alert-dialog
  id="confirm-publish"
  title="Publish this article?"
  confirm-text="Publish"
>
  Once published, “Spring collection 2026” becomes visible to everyone on your storefront. You can
  still edit it afterwards.
</l-alert-dialog>

Danger

Add tone="danger" to render the confirm action as destructive — for delete, discard, or other irreversible actions.

This permanently deletes the Acme project and everything in it. This action cannot be undone.
Code
html
<button
  type="button"
  class="l-button"
  data-variant="destructive"
  command="--show"
  commandfor="confirm-delete"
>
  Delete project
</button>

<l-alert-dialog
  id="confirm-delete"
  tone="danger"
  title="Delete this project?"
  confirm-text="Delete"
>
  This permanently deletes the <strong>Acme</strong> project and everything in it. This action
  cannot be undone.
</l-alert-dialog>

Custom actions

Slot your own confirm / cancel elements — a link, a button with an icon, any tone — to replace the built-in buttons. They still drive the confirm / cancel events. Keep the slotted element focusable.

Jane Cooper will get access to the Acme workspace and can edit all projects. Not now
Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="confirm-invite"
>
  Invite collaborator
</button>

<l-alert-dialog
  id="confirm-invite"
  title="Send this invitation?"
  confirm-text="Send invite"
>
  Jane Cooper will get access to the Acme workspace and can edit all projects.

  <a
    slot="cancel"
    class="l-button"
    href="#confirm-invite"
  >
    Not now
  </a>
  <button
    slot="confirm"
    type="button"
    class="l-button [--background-color:var(--l-color-bg-fill-success-strong)] [--background-color-hover:color-mix(in_oklab,var(--l-color-bg-fill-success-strong)_88%,black)] [--background-color-active:color-mix(in_oklab,var(--l-color-bg-fill-success-strong)_78%,black)] [--text-color:white] [--text-color-hover:white] [--border-color:transparent]"
  >
    <l-icon name="lucide:send"></l-icon>
    Send invite
  </button>
</l-alert-dialog>

Examples

Reacting to the choice

Listen for confirm and cancel. Both fire on the user's intent; the dialog closes on its own afterwards.

js
const dialog = document.getElementById('confirm-delete');

dialog.addEventListener('confirm', () => deleteProject());
dialog.addEventListener('cancel', () => {
  /* optional: the user backed out */
});

Async confirmation

confirm is cancelable. Call preventDefault() to keep the dialog open while an async task runs, set loading to show a spinner on the confirm action, then close it once the work resolves. The cancel action stays operable throughout. Try it — the confirm button stays busy for ~1.8s:

This action cannot be undone. This will permanently delete your account and remove your data from our servers.
Code
html
<button
  type="button"
  class="l-button"
  data-variant="destructive"
  command="--show"
  commandfor="confirm-delete"
>
  Delete account
</button>

<l-alert-dialog
  id="confirm-delete"
  tone="danger"
  title="Are you absolutely sure?"
  confirm-text="Delete account"
>
  This action cannot be undone. This will permanently delete your account and remove your data from
  our servers.
</l-alert-dialog>
js
const dialog = document.getElementById('confirm-delete');

dialog.addEventListener('confirm', async (event) => {
  event.preventDefault(); // keep the dialog open during the request
  dialog.loading = true; // spinner on the confirm action
  await deleteAccount();
  dialog.loading = false;
  dialog.open = false; // close once it's done
});

Accessibility

Criteria

Role

Rendered as a native <dialog> with role="alertdialog" — interruptive modal semantics

WCAG4.1.2
RGAA7.1
Accessible name

The title property renders as an <h2> and names the dialog

WCAG4.1.2
RGAA11.1
Accessible description

The body content is wired as the dialog description via aria-describedby

WCAG4.1.2
Focus management

Focus is trapped inside the modal and lands on the cancel action — the least destructive choice

WCAG2.4.3
RGAA10.7
Focus restoration

Focus returns to the trigger element when the dialog closes

WCAG2.4.3
Motion

Respects prefers-reduced-motion

WCAG2.3.3

Keyboard interactions

Escape
Dismisses the dialog (fires `cancel`)
Tab
Cycles focus through the actions inside the dialog
ShiftTab
Cycles focus backward through the actions

API reference

Importing

js
import 'luxen-ui/alert-dialog';

Attributes & Properties

confirm-textstringdefault:'Confirm'Property
Label for the confirm action.
cancel-textstringdefault:'Cancel'Property
Label for the cancel action.
tone'danger' | undefinedProperty
Visual tone. danger renders the confirm action as destructive.
loadingbooleandefault:falseProperty
Show a busy state on the confirm action (spinner + aria-disabled); the cancel action stays operable as an escape hatch.
titlestringProperty
Dialog title rendered in the header and used as the dialog's accessible name.
openbooleandefault:falseProperty
Whether the dialog is open.
light-dismissbooleandefault:falseProperty
Close when the backdrop is clicked.
without-headerbooleandefault:falseProperty
Hide the header entirely (title and close slot).

Commands

Open and close the dialog by toggling its open property, or via the Invoker Commands API from any light-DOM button. Custom commands must start with --.

--showCommand
Sets open = true.
--hideCommand
Sets open = false.

Events

confirmcancelableEvent
Fired when the user accepts. Cancelable — preventDefault() keeps it open for async work.
cancelcancelableEvent
Fired when the user dismisses (cancel action, Escape). Cancelable — preventDefault() keeps it open.
showcancelableEvent
Fired when the dialog is about to open. Cancelable.
hidecancelableEvent
Fired when the dialog is about to close via the open property. Cancelable. (The confirm, cancel, and Escape paths close natively and emit confirm/cancel instead of hide.)
after-showEvent
Fired after the open animation completes. Not cancelable.
after-hideEvent
Fired after the close animation completes. Not cancelable.

Slots

(default)Slot
Description text. Provides the dialog's accessible description.
titleSlot
Custom heading element. Overrides the default <h2> rendered from the title property. Also provides the dialog's accessible name.
cancelSlot
Replaces the built-in cancel action (e.g. a link). Keep it focusable.
confirmSlot
Replaces the built-in confirm action.
closeSlot
Close button (typically <button class="l-close">).
footerSlot
Footer actions.

CSS parts

dialogPart
The native <dialog> element.
headerPart
The header wrapper containing the title.
titlePart
The dialog title heading.
bodyPart
The body wrapper around the description.
footerPart
The footer wrapper around the actions.
buttonPart
Both built-in action buttons.
cancelPart
The built-in cancel button.
confirmPart
The built-in confirm button.

CSS custom properties

--widthdefault:31remCustom property
Dialog width.
--border-radiusdefault:6pxCustom property
Dialog border radius.
--paddingdefault:1.5remCustom property
Padding applied to the header, footer, and inline-padding of the body.
--show-durationdefault:200msCustom property
Open transition duration.
--hide-durationdefault:200msCustom property
Close transition duration.
--backdropCustom property
Backdrop color.
--backdrop-blurdefault:0Custom property
Backdrop blur amount (any CSS length).