Addaw, ir a inicio Donar

Técnica HTML WCAG 2.2

H102Crear ventanas modales con el elemento dialog de HTML

Nombre oficial en el W3C: Crear diálogos modales con el elemento dialog de HTML

En pocas palabras

Una ventana modal es un cuadro que se abre encima de la página y bloquea el resto hasta que se cierra. Si se crea con el elemento dialog de HTML y se abre con showModal(), el navegador gestiona solo el foco del teclado. Así se evitan los errores típicos de las ventanas hechas a mano.

Por qué es importante

Quien usa el teclado o un lector de pantalla necesita que, al abrirse la ventana, el foco (el punto donde actúa el teclado) entre en ella. También necesita que no pueda salirse a la página de detrás y que, al cerrarla, vuelva al botón que la abrió.

Si falla algo de esto, la persona se pierde. Puede seguir tabulando por la página oculta o quedarse al principio del documento tras cerrar la ventana. Con dialog el navegador hace todo eso por usted.

Cómo se hace

  1. Ponga el contenido de la ventana dentro de <dialog> y dele un título con aria-labelledby.
  2. Ábrala desde un <button type="button"> con el método showModal(). El método show() abre una ventana no modal y no bloquea el resto.
  3. Para cerrarla, use un botón dentro de un <form method="dialog">, o llame a close(). El navegador devuelve el foco al botón que la abrió.
  4. Tenga en cuenta que el foco va al primer elemento enfocable. Si quiere que vaya al título, póngale tabindex="-1" y colóquelo antes del botón de cerrar en el código.
  5. No anule el cierre con la tecla Esc, que el navegador ya ofrece.

Cómo comprobarlo

  1. Abra la ventana con el teclado: llegue al botón con Tab y pulse Intro o la barra espaciadora.
  2. Compruebe que el foco pasa a la ventana o a un elemento de dentro.
  3. Pulse Tab varias veces. El foco no debe llegar a enlaces o botones de la página de detrás.
  4. Cierre con Esc y con el botón de cerrar. El foco debe volver al botón que abrió la ventana.

Ejemplo

Ventana modal para suscribirse al boletín de noticias.

<button type="button" id="abrir">Suscribirse al boletín</button>

<dialog id="boletin" aria-labelledby="tit-boletin">
  <h2 id="tit-boletin" tabindex="-1">Boletín de noticias</h2>
  <!-- formulario de suscripción -->
  <form method="dialog">
    <button>Cerrar</button>
  </form>
</dialog>

<script>
  const boletin = document.getElementById('boletin');
  document.getElementById('abrir')
    .addEventListener('click', () => boletin.showModal());
</script>
Ver el texto completo del W3C (traducción al español)

Esta es una traducción no oficial al español de la técnica H102 de Techniques for WCAG 2.2, del W3C. Puede contener errores. El único documento oficial y normativo es la versión original en inglés, publicada en el sitio web del W3C.

Aplicabilidad

HTML

Descripción

Quienes desarrollan sitios web suelen utilizar diálogos modales para centrar la atención del usuario en una información o en una actividad relacionada con una tarea que queda fuera del ámbito del contenido principal de la página. Los diálogos modales pueden construirse en el marcado mediante la función dialog de ARIA y sus atributos relacionados, o mediante el elemento dialog de HTML. Además de cumplir la primera regla de ARIA, el elemento dialog de HTML ofrece varias ventajas frente a su equivalente en ARIA, ya que el navegador se encarga de estas funciones:

  • el foco del teclado se mueve al dialog modal que se acaba de abrir;
  • el foco del teclado vuelve al elemento que invocó el diálogo (suponiendo que el elemento siga en la página) cuando se cierra el dialog modal;
  • el foco del teclado se limita al contenido del dialog modal y a la interfaz del propio navegador (es decir, la interfaz de usuario específica del navegador, como la barra de direcciones, etc.);
  • el contenido de la página «fuera» del diálogo modal pasa a ser inerte, lo que hace que quede oculto para las tecnologías de asistencia e inoperable para todos los usuarios mientras el dialog modal permanezca abierto;
  • el uso de la tecla Escape para cerrar el dialog modal.

Esta técnica utiliza el elemento dialog de HTML en lugar de una implementación ARIA a medida, lo que reduce el esfuerzo necesario para crear un diálogo modal accesible.

Ejemplos

Un diálogo para suscribirse a una lista de correo

Este es un ejemplo de uso de un elemento dialog modal para mostrar al usuario un formulario de suscripción a una lista de correo. La parte principal de la página contiene un elemento button que, al activarse, invoca el dialog modal. El button usa el atributo type para indicar al navegador que no se trata de un button de tipo submit.

Cuando se abre el dialog modal, el navegador trata todo el contenido que queda fuera del diálogo modal como inerte, de modo que lo vuelve inoperable y lo oculta a las tecnologías de asistencia. Por ejemplo, un lector de pantalla no podrá alcanzar ni anunciar ninguna parte del contenido inerte. Además, como el contenido de la página es inerte, el foco del teclado solo podrá llegar a los elementos enfocables que estén dentro del elemento dialog y a los controles del navegador. Al invocarlo, el navegador coloca automáticamente el foco en el primer elemento enfocable del DOM del diálogo. En este ejemplo, el elemento h1 recibirá el foco porque tiene un atributo tabindex="-1". Tenga en cuenta que, aunque el button de cierre del dialog aparece visualmente antes del h1, es el último elemento del DOM del dialog. Si el button estuviera primero, sería el que recibiría el foco al abrirse el diálogo.

El HTML

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,
     initial-scale=1, shrink-to-fit=no">
    <title>Turbo Encabulator News</title>
  </head>
  <body>
    <main>
      <h1>All The News About Turbo Encabulators</h1>
      <button class="open-modal" type="button">Sign up to our mailing list!</button>
    </main>
    <dialog aria-labelledby="dialog-heading" id="mailing-list-dialog">
      <h1 id="dialog-heading" tabindex="-1">Sign up to our mailing list</h1>
      <form>
        <p class="req-note">All form fields are required.</p>
        <div>
          <label for="fname">First Name</label>
          <input aria-required="true" autocomplete="given-name" id="fname" type="text">
        </div>
        <div>
          <label for="lname">Last Name</label>
          <input aria-required="true" autocomplete="family-name" id="lname" type="text">
        </div>
        <div>
          <label for="email">Email address</label>
          <input aria-required="true" autocomplete="email" id="email" type="text">
        </div>
        <button class="sign-up" type="submit">Sign up</button>
      </form>
     <form method="dialog">
        <button aria-label="close" class="close-modal">&times;</button>
      </form>
    </dialog>
  </body>
</html>

El CSS

*, *::after, *::before {
  box-sizing: inherit;
}
body {
  background:#fff;
  color:#000;
  font:1rem/1.5 system-ui, Helvetica, Roboto, sans-serif;
}
*:focus-visible {
  outline:1px solid #0054AE;
  outline-offset:1px;
}
dialog {
  border:1px solid #000;
  padding:2rem;
  position:relative;
}
dialog::backdrop {
  background-color:hsla(0, 0%, 0%, .5);
}
.close-modal {
  inset-block-start:1.5rem;  
  inset-inline-end:1.5rem;  
  line-height:1.3;
  padding:0.25em 0.5em;
  position:absolute;
}
.sign-up {
  background:#000;
  color:#fff;
  padding:0.25em;
}
dialog h1 {
  display:inline-block;
  line-height:1.3333;
  margin:0;
  max-inline-size:95%;
}
form {
  display:grid;
  grid-gap:20px;
  grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
}
.req-note, .sign-up {
  grid-column:1 / -1;
}
label {
  display:block;
}
input {
  border:1px solid hsl(0, 0%, 50%);
  font:inherit;
  inline-size:calc(100% - 4px);
}
button {
  background:#fff;
  border:1px solid hsl(0, 0%, 50%);
  border-radius:3px;
  color:inherit;
  font:inherit;
  margin:0;
}

El JavaScript

El script es necesario para mostrar el dialog cuando se invoca. El elemento dialog de HTML puede abrirse con dos órdenes distintas: show() (para dialog no modales) y showModal() (para dialog modales), que es la que se usa en este ejemplo.

Nota: en lugar de escribir una función para cerrar el dialog, el botón de cierre está anidado dentro de un elemento form independiente con un atributo method="dialog". Este método permite cerrar el diálogo al activar dicho botón, y el navegador se encargará de devolver el foco del teclado al elemento que lo invocó.

document.addEventListener("DOMContentLoaded", function(e){
  const d = document.querySelector("dialog");
  const btnOpen = document.querySelector(".open-modal");
  btnOpen.addEventListener("click", function(){
    d.showModal();
  }, false);
});

Pruebas

Procedimiento

  1. Localizar los componentes de la página que invocan elementos dialog modales.
  2. Comprobar que cada dialog puede abrirse usando el teclado para activar el elemento que lo invoca (por ejemplo, activar un button pulsando la tecla Intro o la barra espaciadora).
  3. Cuando se abre el dialog modal, comprobar que el foco se ha movido a él o a uno de sus descendientes enfocables.
  4. Mientras el dialog modal está abierto, comprobar que el foco del teclado no puede moverse a los elementos del documento principal.
  5. Cuando se cierra el dialog modal, comprobar que el foco vuelve al elemento que lo invocó, si dicho elemento sigue existiendo en la página.

Resultados esperados

  • Las comprobaciones n.º 2, n.º 3, n.º 4 y n.º 5 son verdaderas.

Recursos

Cómo lo comprobamos en ADDAW

En cada auditoría de ADDAW revisamos esta técnica página a página y le entregamos los errores con capturas y la forma de corregirlos.

Solicitar una auditoría

Basado en la técnica H102 del W3C (WCAG 2.2). Explicación y ejemplos: ADDAW. Traducción no oficial del texto del W3C © W3C, licencia de documentos del W3C. ¿Ha visto un error? Escríbanos.