Un alert dialog es un cuadro de diálogo modal que interrumpe el flujo de trabajo del usuario para comunicarle un mensaje importante que requiere una respuesta inmediata (por ejemplo, confirmar una acción destructiva o avisar de un error grave). Al aplicar el rol alertdialog, las tecnologías asistivas y los navegadores pueden tratarlo de forma especial (p. ej., reproducir un sonido de sistema), diferenciándolo de otros diálogos convencionales.

En el apartado de Ejemplo de implementación podréis ver un ejemplo de implementación de un alert dialog en React.

Estructura semántica mínima

  • El contenedor nativo <dialog> aporta toda la sintaxis semántica que necesita un modal. En casos de necesidad, se puede extender la semántica utilizando role="alertdialog". También podría utilizarse un <div>, pero requerirá más trabajo.
  • Deberá tener un título visible y referenciado con aria-labelledby, para proporcionarle un nombre accesible.
  • Deberá tener un texto del mensaje y referenciado con aria-describedby, para proporcionarle una descripción accesible.
  • Deberá tener botones de acción que permitan responder al mensaje.
  • El foco inicial se envía al botón menos destructivo.

El diálogo debe tener un título y un mensaje legibles para satisfacer el SC1 4.1.2 (Name, Role, Value).

Comportamiento de teclado y gestión del foco

  1. Al abrir el diálogo

    • Mueve el foco al primer control dentro del <dialog>.
    • Guarda la referencia del elemento que abrió el diálogo para restaurarlo al cerrar.
  2. Ciclo de tabulación

    • Tab y Shift + Tab recorren solo los controles del diálogo (focus trap).
    • Evita que el foco se “escape” accidentalmente (SC 2.1.2 No Keyboard Trap).
  3. Salir con Esc

    • Permite cerrar el diálogo con la tecla Esc y devuelve el foco al elemento que abrió el diálogo.
  4. Visibilidad y orden de foco

    • El foco debe seguir un orden lógico (SC 2.4.3 Focus Order) y ser visible (SC 2.4.7 Focus Visible; SC 2.4.11 Focus Not Obscured, nuevo en WCAG 2.2).
  5. Operable solo con teclado

    • Todas las acciones (aceptar, cancelar, cerrar) han de ser ejecutables mediante teclado (SC 2.1.1 Keyboard)

Criterios de éxito (SC) asociados al alert dialog

SCNombreCómo afecta a alertdialogNivel
2.1.1, se abrirá en una nueva pestañaKeyboardToda funcionalidad operable por tecladoA
2.1.2, se abrirá en una nueva pestañaNo Keyboard Trap2El foco no queda atrapado sin salida evidenteA
2.4.3, se abrirá en una nueva pestañaFocus OrderSecuencia de foco lógica dentro y fuera del diálogoA
2.4.7, se abrirá en una nueva pestañaFocus VisibleIndicador de foco perceptibleAA
2.4.11/12, se abrirá en una nueva pestañaFocus Not ObscuredEl elemento con foco no queda oculto por el diálogo ni por el overlayAA/AAA
4.1.2, se abrirá en una nueva pestañaName, Role, Valuerole=“alertdialog”, aria-labelledby, aria-describedbyA
4.1.3, se abrirá en una nueva pestañaStatus MessagesSi el diálogo informa de estado (p. ej. confirmación rápida), usa role=“alert” o alertdialogAA

Buenas prácticas complementarias

  • Anunciar cambios breves (p. ej. “Notas guardadas”) con role="alert" en lugar de alertdialog para no exigir interacción del usuario. No será necesario el role="alert" en caso de utilizar el elemento <dialog>.
  • Mantén la jerarquía de encabezados y el orden DOM para que la secuencia de lectura sea lógica (SC 1.3.2 Meaningful Sequence, se abrirá en una nueva pestaña).
  • Utiliza role="document" y tabindex="0" en el contenedor del diálogo para que los lectores de pantalla puedan identificarlo como el contenido principal del elemento.
  • Minimiza el uso de ARIA. Utiliza el elemento <dialog> y su atributo open de preferencia; añade role="alertdialog" solo cuando sea necesario.
  • Prueba con lectores de pantalla (NVDA, JAWS, VoiceOver) y navegadores móviles.

Lista de verificación rápida

  • El diálogo tiene título (aria-labelledby o aria-label).
  • Hay descripción (aria-describedby) que se lee automáticamente.
  • Se abre mediante un control accesible.
  • Foco inicial en la acción más segura; focus trap.
  • Se cierra con Esc y devuelve el foco al elemento activador.
  • Todos los botones son operables por teclado y muestran foco visible.
  • El diálogo y su foco nunca quedan ocultos detrás de otros elementos.

Ejemplo de implementación

El diálogo tiene título y descripción

<dialog
  role="alertdialog"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-description"
  ...
  >
  ...
    <h2 id="dialog-title">...</h2>
    <p id="dialog-description">...</p>
  ...
</dialog>

Se abre mediante un control accesible

const [isOpen, setIsOpen] = useState(false);
...
<button onClick={() => setIsOpen(true)}>Open dialog</button>

Foco inicial en la acción más segura; focus trap, se cierra con Esc y devuelve el foco al elemento activador.

const handleKeyDown = (event) => {
    if (event.key === "Escape") {
      setIsOpen(false);
    }
  };

  const handleFocusTrap = (event) => {
    if (!isOpen) return;

    const dialog = dialogRef.current;
    if (!dialog) return;

    const focusableElements = dialog.querySelectorAll(
      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    const firstFocusable = focusableElements[0];
    const lastFocusable = focusableElements[focusableElements.length - 1];

    if (event.key === "Tab") {
      if (event.shiftKey && document.activeElement === firstFocusable) {
        event.preventDefault();
        lastFocusable.focus();
      } else if (!event.shiftKey && document.activeElement === lastFocusable) {
        event.preventDefault();
        firstFocusable.focus();
      }
    }
  };

  useEffect(() => {
    ...
    if (isOpen) {
      ...
    } else {
      triggerRef.current?.focus();
    }
    ...
  }, [isOpen]);

Soporte del elemento <dialog> en navegadores

Footnotes

  1. En los documentos de las Pautas de Accesibilidad para el Contenido Web (WCAG), la abreviatura SC significa Success Criterion (criterio de éxito). Cada criterio describe un requisito verificable que el contenido debe cumplir para alcanzar un determinado nivel de conformidad (A, AA o AAA).

  2. La “trampa de teclado” que prohíbe la WCAG 2.1.2 se refiere a quedar atrapado sin salida: si entras en un componente y después no existe ninguna forma de salir solo con el teclado, o necesitas combinaciones no estándar y nadie te las indica. La propia página de No Keyboard Trap (Level A), se abrirá en una nueva pestaña pone como ejemplo válido un diálogo modal cuya tabulación se mantiene dentro de él mientras esté abierto; la clave es que el usuario puede abandonarlo con un botón Cancelar/OK o con la tecla Esc.