Skip to content

Alert Dialog Nuevo

Modal especializado para confirmaciones destructivas. Implementa el patrón WAI-ARIA Alert Dialog: aplica role="alertdialog" automáticamente, bloquea Escape y click en backdrop, y enfoca el botón Cancelar al abrir para prevenir confirmaciones accidentales. Para diálogos descartables convencionales, usa <hp-dialog>.

Demostración

Sin estilos (solo base.css)

Así se ve hp-alert-dialog usando únicamente @headless-primitives/utils/base.css. El focus trap, el bloqueo de ESC y el bloqueo de backdrop funcionan completamente.

¿Confirmar acción irreversible?Esta acción no se puede deshacer.

Con estilos personalizados

Confirmar eliminación¿Estás seguro? Esta acción no se puede deshacer.
html
<hp-alert-dialog>
  <hp-alert-dialog-trigger>
    <button class="open-alert">Eliminar elemento</button>
  </hp-alert-dialog-trigger>
  <hp-alert-dialog-backdrop class="backdrop"></hp-alert-dialog-backdrop>
  <hp-alert-dialog-content class="content">
    <hp-alert-dialog-title>Confirmar eliminación</hp-alert-dialog-title>
    <hp-alert-dialog-description>
      ¿Estás seguro? Esta acción no se puede deshacer.
    </hp-alert-dialog-description>
    <div class="actions">
      <hp-alert-dialog-cancel class="btn">Cancelar</hp-alert-dialog-cancel>
      <hp-alert-dialog-action class="btn danger">Eliminar</hp-alert-dialog-action>
    </div>
  </hp-alert-dialog-content>
</hp-alert-dialog>
css
.backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
}

.content {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: white;
  padding: 1.5rem;
  border-radius: 12px;
  max-width: 400px;
  width: 90%;
}

.actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.5rem;
}

.btn.danger {
  background: #dc2626;
  color: white;
}

Instalación

bash
pnpm add @headless-primitives/alert-dialog
bash
npm install @headless-primitives/alert-dialog
bash
yarn add @headless-primitives/alert-dialog
bash
bun add @headless-primitives/alert-dialog

Features

  • ♿️ role="alertdialog" aplicado automáticamente — el consumidor no debe declararlo a mano.
  • 🔒 Escape NO cierra — exige decisión explícita del usuario.
  • 🖱️ Click en backdrop NO cierra.
  • 🎯 Foco inicial cae en <hp-alert-dialog-cancel> (W3C APG).
  • 🎨 Sin estilos visuales (Headless) — posicionamiento via base.css.

Anatomía

html
<hp-alert-dialog>
  <hp-alert-dialog-trigger></hp-alert-dialog-trigger>
  <hp-alert-dialog-backdrop></hp-alert-dialog-backdrop>
  <hp-alert-dialog-content>
    <hp-alert-dialog-title></hp-alert-dialog-title>
    <hp-alert-dialog-description></hp-alert-dialog-description>
    <hp-alert-dialog-cancel></hp-alert-dialog-cancel>
    <hp-alert-dialog-action></hp-alert-dialog-action>
  </hp-alert-dialog-content>
</hp-alert-dialog>

API Reference

hp-alert-dialog

Contenedor raíz. Coordina apertura/cierre, focus trap, scroll lock y enrutamiento de eventos hp-cancel / hp-action hacia el cierre.

Eventos

EventoDetalleDescripción
hp-openSe emite cuando el alert dialog se abre.
hp-closeSe emite cuando el alert dialog se cierra (también al activar cancel o action).
hp-cancelSe emite cuando el usuario activa <hp-alert-dialog-cancel> (antes del cierre).
hp-actionSe emite cuando el usuario activa <hp-alert-dialog-action> (antes del cierre).

Métodos

MétodoDescripción
open()Abre el alert dialog programáticamente.
close()Cierra el alert dialog programáticamente.

hp-alert-dialog-trigger

Elemento que abre el alert dialog al hacer click.

Atributos / Propiedades

Atributo / PropiedadTipoPor DefectoDescripción
disabledbooleanfalseDeshabilita el trigger.

Atributos ARIA gestionados automáticamente

  • role="button" — Asignado si no se especifica.
  • tabindex="0" — Habilitado cuando no está deshabilitado.
  • aria-expanded"true" cuando el alert está abierto, "false" cuando cerrado.
  • aria-controls — ID del content cuando abierto.
  • aria-disabled — Sincronizado con el estado disabled.

hp-alert-dialog-content

Contenedor del contenido modal con focus trap. El componente aplica el role correcto sin que el consumidor lo declare.

Atributos ARIA gestionados automáticamente

  • role="alertdialog" — Aplicado siempre.
  • aria-modal="true" — Aplicado siempre.
  • aria-hidden"true" cuando cerrado, ausente cuando abierto.
  • aria-labelledby — Vinculado al ID del <hp-alert-dialog-title> si existe.
  • aria-describedby — Vinculado al ID del <hp-alert-dialog-description> si existe.
  • data-state"open" | "closed".
  • data-hp-overlay-content — Presente siempre (usado por base.css para posicionamiento fijo).
  • id — Generado automáticamente si no se proporciona.

hp-alert-dialog-backdrop

Overlay visual. No registra listener de click: a diferencia de hp-dialog, el alert dialog requiere acción explícita.

Atributos ARIA gestionados automáticamente

  • data-hp-backdrop — Presente siempre.
  • data-state"open" | "closed".

hp-alert-dialog-title

Título semántico. Auto-asigna un id si no se proporciona y el content lo enlaza vía aria-labelledby.

hp-alert-dialog-description

Texto descriptivo. Auto-asigna un id si no se proporciona y el content lo enlaza vía aria-describedby.

hp-alert-dialog-cancel

Botón cancelar. Recibe el foco inicial al abrir (W3C APG: la opción más segura debe ser la predeterminada). Al activarse emite hp-cancel y dispara el cierre.

Atributos ARIA gestionados automáticamente

  • role="button" — Asignado si no se especifica.
  • tabindex="0" — Siempre focusable.

hp-alert-dialog-action

Botón confirmar (acción destructiva). Al activarse emite hp-action y dispara el cierre. Escucha el evento hp-action en el root para ejecutar tu lógica antes/después del cierre.

Atributos ARIA gestionados automáticamente

  • role="button" — Asignado si no se especifica.
  • tabindex="0" — Siempre focusable.

Accesibilidad

Adhiere al patrón WAI-ARIA APG para Alert Dialog.

TeclaAcción
EscapeNO cierra el alert dialog (requiere acción explícita).
TabNavega entre elementos focusables dentro del dialog (focus trap).
Shift + TabNavega en reversa dentro del focus trap.
Enter / SpaceActiva el trigger, cancel, action o cualquier botón focusable interno.

Foco inicial

Al abrir, el foco aterriza en <hp-alert-dialog-cancel> siguiendo la recomendación W3C: prevenir confirmaciones accidentales colocando el cursor en la opción reversible/segura por defecto.

Ejemplos

Reaccionar a la confirmación antes del cierre

html
<hp-alert-dialog id="delete-dialog">
  <hp-alert-dialog-trigger><button>Delete account</button></hp-alert-dialog-trigger>
  <hp-alert-dialog-backdrop></hp-alert-dialog-backdrop>
  <hp-alert-dialog-content>
    <hp-alert-dialog-title>Delete account?</hp-alert-dialog-title>
    <hp-alert-dialog-description>
      This action permanently removes all your data.
    </hp-alert-dialog-description>
    <hp-alert-dialog-cancel>Cancel</hp-alert-dialog-cancel>
    <hp-alert-dialog-action>Delete</hp-alert-dialog-action>
  </hp-alert-dialog-content>
</hp-alert-dialog>

<script>
  const root = document.getElementById("delete-dialog");
  root.addEventListener("hp-action", async () => {
    await fetch("/api/account", { method: "DELETE" });
    // hp-close ya se disparó después de hp-action; aquí lanza navegación, toast, etc.
    location.href = "/goodbye";
  });
  root.addEventListener("hp-cancel", () => {
    console.log("User cancelled");
  });
</script>

Control programático

javascript
const dialog = document.querySelector("hp-alert-dialog");

dialog.open();
dialog.close();

dialog.addEventListener("hp-open", () => console.log("opened"));
dialog.addEventListener("hp-close", () => console.log("closed"));

Lanzado bajo la MIT License.