---
outline: deep
---

# Alert dialog

An interruptive confirmation dialog built on [`<l-dialog>`](./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.

**`<l-alert-dialog>`** — Custom Element · Shadow DOM

## 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.

```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.

```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.

```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:

<ComponentWrapper>
  <button type="button" class="l-button" data-variant="destructive" command="--show" commandfor="async-confirm-demo">
    Delete account
  </button>
  <l-alert-dialog id="async-confirm-demo" 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>
</ComponentWrapper>

```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
- **Accessible name** — The `title` property renders as an `<h2>` and names the dialog
- **Accessible description** — The body content is wired as the dialog description via `aria-describedby`
- **Focus management** — Focus is trapped inside the modal and lands on the cancel action — the least destructive choice
- **Focus restoration** — Focus returns to the trigger element when the dialog closes
- **Motion** — Respects `prefers-reduced-motion`

### Rules

- Always set a meaningful `title` — it becomes the dialog heading and accessible name
- Write a body that describes the consequence — it becomes the accessible description
- Reserve `tone="danger"` for irreversible actions
- When slotting a custom action, keep it focusable (a `<button>` or `<a href>`)

### Keyboard interactions

- `Escape` — Dismisses the dialog (fires `cancel`)
- `Tab` — Cycles focus through the actions inside the dialog
- `Shift + Tab` — Cycles focus backward through the actions

## API reference

### Importing

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

### Attributes & Properties

- **confirm-text**: `string` (default: `'Confirm'`) — Label for the confirm action.
- **cancel-text**: `string` (default: `'Cancel'`) — Label for the cancel action.
- **tone**: `'danger' | undefined` — Visual tone. `danger` renders the confirm action as destructive.
- **loading**: `boolean` (default: `false`) — Show a busy state on the confirm action (spinner + `aria-disabled`); the
cancel action stays operable as an escape hatch.
- **title**: `string` — Dialog title rendered in the header and used as the dialog's accessible name.
- **open**: `boolean` (default: `false`) — Whether the dialog is open.
- **light-dismiss**: `boolean` (default: `false`) — Close when the backdrop is clicked.
- **without-header**: `boolean` (default: `false`) — 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](https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API) from any light-DOM button. Custom commands must start with `--`.

- `--show` — Sets `open = true`.
- `--hide` — Sets `open = false`.

### Events

- **confirm** (cancelable) — Fired when the user accepts. Cancelable — `preventDefault()` keeps it open for async work.
- **cancel** (cancelable) — Fired when the user dismisses (cancel action, Escape). Cancelable — `preventDefault()` keeps it open.
- **show** (cancelable) — Fired when the dialog is about to open. Cancelable.
- **hide** (cancelable) — 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-show** — Fired after the open animation completes. Not cancelable.
- **after-hide** — Fired after the close animation completes. Not cancelable.

### Slots

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

### CSS parts

- `dialog` — The native `<dialog>` element.
- `header` — The header wrapper containing the title.
- `title` — The dialog title heading.
- `body` — The body wrapper around the description.
- `footer` — The footer wrapper around the actions.
- `button` — Both built-in action buttons.
- `cancel` — The built-in cancel button.
- `confirm` — The built-in confirm button.

### CSS custom properties

- `--width` (default: `31rem`) — Dialog width.
- `--border-radius` (default: `6px`) — Dialog border radius.
- `--padding` (default: `1.5rem`) — Padding applied to the header, footer, and inline-padding of the body.
- `--show-duration` (default: `200ms`) — Open transition duration.
- `--hide-duration` (default: `200ms`) — Close transition duration.
- `--backdrop` — Backdrop color.
- `--backdrop-blur` (default: `0`) — Backdrop blur amount (any CSS length).
