Normativas · ARIA

Rol Ventana

dialog

Marca un contenedor como un diálogo modal o no modal. Utilice el elemento nativo <dialog> con showModal() — gestiona de forma automática el confinamiento del foco, la capa superior, el telón de fondo y el cierre con Escape. Recurra a role="dialog" solo cuando el elemento nativo sea imposible de usar.

Cuándo utilizarlo

Utilice <dialog> abierto mediante .showModal(). El elemento nativo es compatible con todos los navegadores actuales y gestiona automáticamente el fondo inactivo, el confinamiento del foco, el cierre con Escape, el gancho de estilos ::backdrop y la representación en la capa superior. Esto le ahorra alrededor de 200 líneas de JavaScript frágil.

Recurra a role="dialog" sobre un <div> únicamente cuando:

  • Se admiten navegadores anteriores a Chrome 37 / Firefox 98 / Safari 15.4 (improbable en 2026).
  • El diseño exige un diálogo que no pueda situarse en la capa superior (poco frecuente).
  • Se está corrigiendo un modal personalizado inaccesible durante una refactorización.

Todo diálogo DEBE tener un nombre accesible (aria-labelledby apuntando a un encabezado visible es el patrón más sólido). Los diálogos modales también requieren aria-modal="true".

Contrato de teclado y foco

Según el patrón APG de diálogo modal:

  • Al abrirse, el foco se desplaza al primer elemento enfocable dentro del diálogo (habitualmente el botón de cierre o el campo principal).
  • Tab y Shift+Tab ciclan el foco DENTRO del diálogo — una «trampa de foco». Tab desde el último elemento regresa al primero; Shift+Tab desde el primero regresa al último.
  • Escape cierra el diálogo.
  • Al cerrarse, el foco regresa al elemento que abrió el diálogo. Guardar y restaurar el foco es imprescindible; los usuarios que pierden su posición se quedan sin referencia.
  • El resto de la página permanece inert (o aria-hidden="true" más no enfocable como alternativa) mientras el diálogo está abierto.

Fallos frecuentes

  • Diálogo personalizado sin trampa de foco. Tab escapa del diálogo y va detrás de él; los usuarios pierden el contexto.
  • Foco no restaurado al desencadenador al cerrar. El siguiente Tab aterriza en el cuerpo del documento.
  • El contenido de fondo sigue siendo accesible mediante Tab aunque esté visualmente oculto detrás del diálogo.
  • Sin nombre accesible. El diálogo se abre y el lector de pantalla anuncia únicamente «dialog».
  • Diálogo personalizado sin aria-modal="true" — la tecnología de asistencia lo trata como contenido en línea.
  • Escape cierra el diálogo, pero este se renderiza a través de un portal que pierde el foco de teclado durante la animación de cierre.

Ejemplo

<!-- Preferido -->
<dialog id="confirm">
  <h2>¿Eliminar este borrador?</h2>
  <p>Esta acción no se puede deshacer.</p>
  <form method="dialog">
    <button value="cancel">Cancelar</button>
    <button value="delete" autofocus>Eliminar</button>
  </form>
</dialog>
<script>
  document.getElementById('confirm').showModal();
</script>

<!-- Cuando <dialog> es imposible -->
<div role="dialog" aria-modal="true" aria-labelledby="dlgTitle">
  <h2 id="dlgTitle">Editar perfil</h2>

</div>