Addaw, ir a inicio Donar

Lección 6 de 10 · 20 min de lectura · Revisado el 26/10/2026

Diálogos modales, acordeones y tooltips

Estos tres componentes tienen en común que muestran y ocultan contenido, y se diferencian en cuánto interrumpen: el diálogo modal detiene todo lo demás, el acordeón despliega en su sitio y el tooltip asoma un momento. Cada uno tiene su patrón en la APG (se abre en una ventana nueva) y, desde WCAG 2.1, el contenido que aparece al pasar el puntero o al enfocar tiene su propio criterio, 1.4.13 Contenido con hover o foco (AA). Esta lección los recorre con el código mínimo correcto y los fallos que más se repiten.

Diálogos modales

Vimos la gestión del foco en el curso de teclado; aquí completamos la estructura. Un diálogo modal accesible necesita:

  • Rol dialog (o alertdialog si es un aviso que exige respuesta) y aria-modal="true", ambos implícitos en <dialog> abierto con showModal().
  • Nombre accesible con aria-labelledby apuntando a su título, que debe ser un encabezado (normalmente <h2>).
  • Opcionalmente aria-describedby apuntando al párrafo explicativo, para que el lector lo lea al abrir.
  • Foco inicial dentro, ciclo del foco, Escape para cerrar, fondo inerte y devolución del foco al cerrar.
  • Un botón de cierre con nombre («Cerrar») además de la Escape, porque no todo el mundo conoce la tecla y en móvil no existe.
  • Que el contenido se pueda desplazar si no cabe en pantalla, incluso al 400 % de zoom, sin quedar cortado.

Ejemplo

<dialog id="dlg-plazo" aria-labelledby="dlg-plazo-t" aria-describedby="dlg-plazo-d">
  <h2 id="dlg-plazo-t">Ampliar el plazo de entrega</h2>
  <p id="dlg-plazo-d">Puedes solicitar hasta 10 días naturales adicionales.</p>
  <form method="dialog">
    <label for="dias">Días adicionales</label>
    <input type="number" id="dias" min="1" max="10">
    <button type="submit" value="cancelar" formnovalidate>Cancelar</button>
    <button type="submit" value="ampliar">Solicitar ampliación</button>
  </form>
</dialog>

Con method="dialog" los botones cierran el diálogo y dialog.returnValue indica cuál se pulsó; formnovalidate permite cancelar aunque el campo tenga un valor no válido. El evento close es el lugar para devolver el foco al botón que lo abrió.

Si el diálogo no es modal (un panel de ayuda que convive con la página), no uses aria-modal ni bloquees el fondo; ábrelo con show() y permite que Tab salga de él. Y una regla de diseño: los diálogos que se abren solos al cargar la página (promociones, suscripción al boletín) son un cambio de contexto no solicitado y una barrera para todo el mundo; si son inevitables (aviso de cookies), deben ser lo primero que recibe el foco y cerrarse con un botón claro.

Acordeones

Un acordeón es una pila de secciones cuyo contenido se despliega al pulsar su cabecera. El patrón de la APG es sencillo porque se apoya en elementos nativos: cada cabecera es un encabezado que contiene un botón con aria-expanded y aria-controls; el panel es un contenedor con id que se muestra u oculta.

<h3>
  <button type="button" aria-expanded="false" aria-controls="acc-1" id="acc-1-b">
    ¿Qué documentación necesito?
  </button>
</h3>
<div id="acc-1" role="region" aria-labelledby="acc-1-b" hidden>
  <p>…</p>
</div>

El encabezado mantiene la estructura de la página (la persona puede saltar entre secciones con la tecla H) y el botón aporta el teclado. Intro y Espacio alternan; opcionalmente, las flechas arriba y abajo mueven el foco entre cabeceras. No es obligatorio que solo una sección esté abierta a la vez; de hecho, permitir varias abiertas evita que se cierre lo que la persona estaba leyendo. El role="region" en el panel es opcional y solo recomendable si hay pocas secciones; con muchas, satura la lista de landmarks.

Una alternativa nativa cada vez más viable es <details> y <summary>: el navegador aporta el botón, el estado expandido/contraído y el teclado sin JavaScript. Sus limitaciones: el summary no puede ser a la vez un encabezado en todos los navegadores de forma consistente, y el estilo del marcador varía. Para preguntas frecuentes y contenidos secundarios es una gran opción.

Error frecuente

Ocultar el panel solo con height: 0; overflow: hidden para animar la apertura. El contenido sigue en el árbol de accesibilidad y el lector lo lee aunque esté «cerrado», y los enlaces de dentro siguen recibiendo el foco. Combina la animación con hidden o display:none al terminar, o usa visibility: hidden, que sí lo retira del árbol.

Tooltips y 1.4.13

Un tooltip es un texto breve que aparece al pasar el puntero o enfocar un elemento. El criterio 1.4.13 impone tres condiciones a cualquier contenido que aparezca así (tooltips, submenús en hover, vistas previas, tarjetas de perfil):

  1. Descartable: debe poder cerrarse sin mover el puntero ni el foco, normalmente con Escape, salvo que no tape nada ni sea un error.
  2. Señalable: si aparece al pasar el puntero, la persona debe poder mover el puntero sobre el contenido sin que desaparezca (quien usa magnificador necesita llegar hasta él).
  3. Persistente: permanece visible hasta que se retira el puntero o el foco, se descarta o deja de ser válido. Nada de desaparecer a los dos segundos.
<button type="button" aria-describedby="tip-guardar">
  <svg aria-hidden="true">…</svg> Guardar
</button>
<div role="tooltip" id="tip-guardar" hidden>Guarda el borrador sin enviarlo (Ctrl+S)</div>

El role="tooltip" con aria-describedby hace que el lector lea el texto como descripción al enfocar el botón; la visibilidad se controla con mouseenter/mouseleave (sin ocultarlo mientras el puntero esté sobre el propio tooltip) y focus/blur, y Escape lo oculta. Dos límites importantes: un tooltip es descripción, no nombre (si el botón solo tiene un icono, necesita nombre aparte), y no debe contener elementos interactivos: lo que necesita enlaces o botones no es un tooltip, es un popover o un diálogo no modal que debe recibir el foco.

El atributo title genera un tooltip nativo, pero no cumple 1.4.13 (no es descartable ni señalable), no aparece con el teclado en la mayoría de los navegadores ni en pantallas táctiles. No lo uses como única forma de dar información.

Punto clave

Diálogo: <dialog> + showModal() + título enlazado + botón de cierre. Acordeón: encabezado que contiene un botón con aria-expanded y panel con hidden (o <details>). Tooltip: role="tooltip" + aria-describedby + descartable con Escape, señalable y persistente.

Cómo comprobarlo

  • Diálogos: abre con teclado, tabula hasta dar la vuelta, pulsa Escape, comprueba dónde vuelve el foco; haz zoom al 400 % y verifica que puedes llegar a todos los botones.
  • Acordeones: con el lector, comprueba que la cabecera se anuncia como encabezado y botón con su estado; con el panel cerrado, el contenido no debe leerse ni enfocarse.
  • Tooltips: pásales el puntero y pulsa Escape; mueve el puntero desde el elemento hasta el tooltip; espera diez segundos y confirma que sigue ahí; enfoca con Tab y escucha la descripción.

Resumen

  • Un diálogo modal tiene rol dialog, nombre por aria-labelledby, foco gestionado, fondo inerte, Escape y botón «Cerrar»; <dialog> con showModal() lo resuelve casi todo.
  • Un acordeón es un encabezado con un botón con aria-expanded y aria-controls y un panel oculto con hidden; <details> es la alternativa nativa.
  • Ocultar con height: 0 no retira el contenido del árbol de accesibilidad.
  • Un tooltip usa role="tooltip" y aria-describedby, es descripción (no nombre) y no contiene elementos interactivos.
  • 1.4.13 exige que todo contenido que aparece con el puntero o el foco sea descartable, señalable y persistente; title no lo cumple.

Comprueba lo que has aprendido

Esta lección se puede leer libremente. Para hacer su test de 3 preguntas, los ejercicios prácticos con páginas reales, guardar tu avance y optar al examen y al certificado, matricúlate en el curso.