Dialog

Un diálogo modal es un tipo especial de cuadro emergente en una página web: una ventana emergente que interrumpe al usuario para que se concentre en sí mismo. Existen algunos casos de uso válidos para crear un diálogo emergente, pero se deben evaluar detenidamente antes de hacerlo. Los diálogos modales obligan a los usuarios a enfocarse en contenido específico y, al menos temporalmente, ignoran el resto de la página.

Los diálogos pueden ser modales (solo se puede interactuar con su contenido) o no modales (aun así, 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 HTML semántico <dialog> para crear un diálogo incluye semántica, interacciones con el teclado y todas las propiedades y métodos de la interfaz HTMLDialogElement.

A continuación, se muestra un ejemplo de un <dialog> modal. Abre el cuadro de diálogo con el botón "Abrir diálogo modal". Una vez abierto, hay tres maneras de cerrar el diálogo: mediante la tecla de escape, mediante el envío de un formulario con un botón que tenga configurado formmethod="dialog" (o si el formulario en sí tiene configurado method="dialog") y el método HTMLDialogElement.close().

HTMLDialogElement tiene tres métodos principales, junto con 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ó a través del método HTMLDialogElement.showModal(), es un diálogo modal. Si abres un diálogo modal, se desactiva y se oculta todo, excepto 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 configurado pointer-events: none;; incluso el botón que abre el diálogo no reacciona a las interacciones.

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

Cuando se cierra un diálogo, es modal o no, el foco se devuelve al elemento que lo abrió. Si abres un diálogo de manera programática no basado en la acción del usuario, reconsidera tu decisión. Si es necesario, asegúrate de que el enfoque vuelva a su estado anterior a la apertura del diálogo, en especial si el usuario descarta el diálogo sin interactuar con él.

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

El fondo que oculta todo excepto 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 FullScreen, como cuando se ve 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 provocar que algo se vuelva inerte. La tecla de escape no cierra diálogos no modales. Debido a esto, es aún más importante asegurarte de incluir un método para cerrar el diálogo no modal. De esta manera, si el cierre está fuera del diálogo, ten en cuenta que el foco 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 exige oficialmente un botón para cerrar el diálogo, considéralo como obligatorio. La clave de escape cerrará un diálogo modal, pero no uno no modal. Un botón visible que puede recibir el foco 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. Para cerrar <dialog> sin JavaScript, incluye un formulario con un método de diálogo configurando method="dialog" en <form> o formmethod="dialog" en el botón.

Cuando un usuario envía información a través del método dialog, se mantiene el estado de los datos que ingresó el usuario. Mientras haya un evento de envío (el formulario pasa por un proceso de 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>

En este ejemplo, es posible que hayas notado el atributo autofocus configurado en el <button> de cierre. Los elementos con el atributo autofocus establecido en un <dialog> no se enfocarán en la carga de la página (a menos que esta 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 otro elemento dentro del diálogo tenga configurado el atributo autofocus. Configurar el atributo autofocus en el botón de cierre garantiza que reciba el foco 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 aparecen antes del elemento de enfoque automático. Analizaremos este atributo con más detalle en la lección de enfoque.

La interfaz HTMLDialogElement incluye una propiedad returnValue. Cuando se envía un formulario con un method="dialog", se configura el returnValue en el name (si hay alguno) 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, está presente el atributo booleano open, 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 hacerlo a través de .show() o .showModal(), el diálogo no será modal. La propiedad HTMLDialogElement.open muestra true o false, según si el diálogo está disponible para interacción (no si es modal o no).

Si bien JavaScript es el método preferido para abrir un diálogo, incluido el atributo open cuando se carga 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 usar tabindex

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

Funciones de ARIA

La función implícita es dialog. Si el diálogo es una ventana de confirmación que comunica un mensaje importante que requiere una confirmación u otra respuesta del usuario, configura role="alertdialog". El diálogo también debe tener un nombre accesible. Si aparece texto visible para el nombre de accesibilidad, agrega aria-labelledby="idOfLabelingText".

Valores predeterminados de CSS

Ten en cuenta que los navegadores proporcionan el estilo predeterminado para dialog. Firefox, Chrome y Edge configuran color: CanvasText; background-color: Canvas;, y Safari configuran color: black; background-color: white; en las hojas de estilo del usuario-agente. color se hereda de dialog y no de body ni :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 diseñas el á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.