Cuadro de diálogo

El elemento dialog es útil para representar cualquier tipo de diálogo en HTML. Descubre cómo funciona.

Un diálogo modal es un tipo especial de cuadro emergente en una página web que interrumpe al usuario para que se concentre en él. Existen algunos casos de uso válidos para mostrar un diálogo, pero se debe tener en cuenta cuidadosamente antes de hacerlo. Los diálogos modales obligan a los usuarios a enfocarse en contenido específico y, al menos temporalmente, ignorar el resto de la página.

Los diálogos pueden ser modales (solo se puede interactuar con el contenido del diálogo) o no modales (aún es posible interactuar con el contenido fuera del diálogo). Los diálogos modales se muestran sobre el resto del contenido de la página. El resto de la página es inerte y, de forma predeterminada, está oculto por un fondo semitransparente.

El elemento <dialog> de HTML semántico para crear un diálogo incluye semántica, interacciones con el teclado y todas las propiedades y métodos de la interfaz HTMLDialogElement.

Este es un ejemplo de un modal <dialog>. Abre el diálogo con el botón "Abrir diálogo modal". Una vez que se abre, hay tres formas de cerrar el diálogo: con la tecla Escape, enviando un formulario con un botón que tenga el atributo formmethod="dialog" establecido (o si el formulario en sí tiene establecido el atributo method="dialog") y con el método HTMLDialogElement.close().

HTMLDialogElement tiene tres métodos principales, además de todos los métodos heredados de HTMLElement.

dialog.show() /* opens the dialog */
dialog.showModal() /* opens the dialog as a modal */
dialog.close() /* closes the dialog */

Como este <dialog> se abrió con el método HTMLDialogElement.showModal(), es un diálogo modal. Cuando se abre un diálogo modal, se desactiva y se oculta todo lo que no sea el diálogo en sí. Si colocas el cursor sobre la IU fuera del diálogo, notarás que todos los elementos se comportan como si se hubiera establecido pointer-events: none;. Incluso el botón que abre el diálogo no reacciona a las interacciones.

Cuando se abre el diálogo, el enfoque se mueve hacia él. El enfoque se establece en el primer elemento del orden de navegación secuencial con el teclado dentro de ese diálogo. Si presionas la tecla tab varias veces, solo el contenido del diálogo puede obtener el enfoque mientras el diálogo modal está abierto. Todo lo que está fuera del diálogo modal es inerte mientras el diálogo esté abierto.

Cuando se cierra un diálogo, ya sea modal o no, el foco regresa al elemento que abrió el diálogo. Evita abrir un diálogo de forma programática sin una acción del usuario. Si es necesario, asegúrate de que el enfoque vuelva a donde estaba antes de que se abriera el diálogo, en especial si el usuario lo descarta sin interactuar con él.

Hay un atributo global inert que se puede usar para inhabilitar un elemento y todos sus elementos secundarios, excepto cualquier diálogo activo. Cuando se abre un diálogo modal con showModal(), la inercia o desactivación se incluyen con él; el atributo no se establece de forma explícita.

El fondo que oculta todo lo que no es el diálogo se puede diseñar con el seudoelemento ::backdrop. El fondo solo se muestra cuando se muestra un <dialog> con el método .showModal(). Este seudoelemento coincide con todos los fondos, incluido el que se muestra cuando se usa la API de pantalla completa, como cuando se mira un video en modo de pantalla completa que no tiene la misma relación de aspecto que la pantalla o el monitor.

Diálogos no modales

De manera similar, HTMLDialogElement.show() abre un diálogo, pero sin agregar un fondo ni hacer que nada se vuelva inerte. La tecla de escape no cierra los diálogos no modales. Por este motivo, es aún más importante incluir un método para cerrar el diálogo no modal. Si el botón de cierre está fuera del diálogo, ten en cuenta que el enfoque se dirigirá al elemento que abrió el diálogo, lo que podría no ser la mejor experiencia del usuario.

Si bien la especificación no requiere oficialmente un botón para cerrar el diálogo, considéralo como obligatorio. La tecla de escape cerrará un diálogo modal, pero no uno no modal. Un botón visible que puede recibir el enfoque mejora la accesibilidad y la experiencia del usuario.

Cómo cerrar un diálogo

No necesitas el método HTMLDialogElement.close() para cerrar un diálogo. No necesitas JavaScript en absoluto. Para cerrar el elemento <dialog> sin JavaScript, incluye un formulario con un método de diálogo configurando method="dialog" en el elemento <form> o formmethod="dialog" en el botón.

Cuando un usuario envía datos con el método dialog, se mantiene el estado de los datos ingresados por el usuario. Si bien hay un evento de envío (el formulario pasa por la validación de restricciones, a menos que se establezca novalidate), los datos del usuario no se borran ni se envían. Un botón de cierre sin JavaScript se puede escribir de la siguiente manera:

<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>

Es posible que hayas notado el atributo autofocus establecido en el cierre <button> en este ejemplo. Los elementos con el atributo autofocus establecido dentro de un <dialog> no recibirán el enfoque cuando se cargue la página (a menos que la página se cargue con el diálogo visible). Sin embargo, se enfocarán cuando se abra el diálogo.

De forma predeterminada, cuando se abre un diálogo, el primer elemento enfocable dentro del diálogo recibirá el enfoque, a menos que un elemento diferente dentro del diálogo tenga establecido el atributo autofocus. Configurar el atributo autofocus en el botón de cierre garantiza que reciba el enfoque cuando se abra el diálogo. Sin embargo, incluir autofocus dentro de un <dialog> solo debe hacerse con mucha consideración. Se omiten todos los elementos de la secuencia que preceden al elemento enfocado automáticamente. Analizamos este atributo con más detalle en la lección de enfoque.

La interfaz HTMLDialogElement incluye una propiedad returnValue. Si se envía un formulario con un method="dialog", se establece el returnValue en el name, si existe, del botón de envío que se usó para enviar el formulario. Si hubiéramos escrito <button type="submit" name="toasty">close</button>, el returnValue sería toasty.

Cuando se abre un diálogo, el atributo booleano open está presente, lo que significa que el diálogo está activo y se puede interactuar con él. Cuando se abre un diálogo agregando el atributo open en lugar de con .show() o .showModal(), el diálogo no será modal. La propiedad HTMLDialogElement.open devuelve true o false, según si el diálogo está disponible para la interacción, no si es modal o no.

Si bien JavaScript es el método preferido para abrir un diálogo, incluir el atributo open en la carga de la página y, luego, quitarlo con .close() puede ayudar a garantizar que el diálogo esté disponible incluso cuando JavaScript no lo esté.

Detalles adicionales

No uses tabindex

El elemento que se activa para abrir el diálogo y el botón de cierre que contiene (y posiblemente otro contenido) pueden recibir el enfoque y son interactivos. El elemento <dialog> no es interactivo y no recibe el enfoque. No agregues la propiedad tabindex al diálogo en sí.

Roles de ARIA

El rol implícito es dialog. Si el diálogo es una ventana de confirmación que comunica un mensaje importante que requiere una confirmación o alguna otra respuesta del usuario, establece role="alertdialog". El diálogo también debe tener un nombre accesible. Si el texto visible puede proporcionar el nombre accesible, agrega aria-labelledby="idOfLabelingText".

Valores predeterminados de CSS

Ten en cuenta que los navegadores proporcionan un diseño predeterminado para dialog. Firefox, Chrome y Edge establecen color: CanvasText; background-color: Canvas;, y Safari establece color: black; background-color: white; en sus hojas de estilo de agente de usuario. El color se hereda de dialog y no de body o :root, lo que puede ser inesperado. La propiedad background-color no se hereda.

Verifica tus conocimientos

Pon a prueba tus conocimientos sobre el elemento de diálogo.

¿Cómo se aplica un diseño al área detrás del diálogo?

Con el seudoelemento ::background
Vuelve a intentarlo.
Con el seudoelemento ::backdrop
Correcto.
Con la propiedad background
Vuelve a intentarlo.