Saltar al contenido
Desarrollo

¿Cómo hago accesibles los componentes interactivos más comunes: menú desplegable, acordeón, tooltip, pestañas y carrusel?

5 min de lectura · WCAG: 1.4.13 Contenido con hover o foco, 2.1.1 Teclado, 2.2.2 Pausar, detener, ocultar, 4.1.2 Nombre, función, valor (Nivel A y AA)

Escrita por Mapa Bianchi

Por qué importa

Los componentes interactivos son donde más fallan los sitios: funcionan con el mouse y se traban con el teclado, o anuncian algo distinto de lo que hacen. ARIA sirve para describir lo que el HTML no puede, pero usado de más o mal confunde más de lo que ayuda. La primera regla es usar HTML nativo siempre que exista.

Un botón con aria-expanded y una lista de enlaces. Sin roles de menú:

<nav aria-label="Cuenta">
  <button type="button" aria-expanded="false" aria-controls="menu-cuenta">
    Mi cuenta
  </button>
  <ul id="menu-cuenta" hidden>
    <li><a href="/perfil">Mi perfil</a></li>
    <li><a href="/configuracion">Configuración</a></li>
    <li><a href="/salir">Cerrar sesión</a></li>
  </ul>
</nav>
  • El botón se abre y cierra con Enter o la barra espaciadora, y cambia aria-expanded.
  • Los enlaces se recorren con Tab, como cualquier enlace.
  • Escape cierra la lista y devuelve el foco al botón.

Los roles menu y menuitem quedan para menús de aplicación (Archivo, Editar, Ver), donde sí se navega con flechas.

Acordeón

La opción más simple es nativa: <details> y <summary> ya se abren con teclado y anuncian su estado.

<details>
  <summary>¿Qué es AxD?</summary>
  <p>Una guía práctica de accesibilidad para quienes publican contenido y quienes hacen webs.</p>
</details>

Si necesitás que abrir una sección cierre las demás o un control fino de la animación, usá botones dentro de títulos:

<h3>
  <button type="button" aria-expanded="false" aria-controls="panel-1" id="boton-1">
    ¿Cómo hago una auditoría manual?
  </button>
</h3>
<div id="panel-1" role="region" aria-labelledby="boton-1" hidden>
  <p>Combiná la navegación con teclado y las pruebas con lector de pantalla.</p>
</div>

El título mantiene la estructura de la página y el botón dice si el panel está abierto. Usá role="region" solo si hay pocos paneles: con muchos, suma ruido.

Tooltip

Un texto que aparece al enfocar o pasar el mouse. Complementa el nombre del control, no lo reemplaza:

<button type="button" aria-describedby="ayuda-guardar">Guardar borrador</button>
<div id="ayuda-guardar" role="tooltip" hidden>
  Guarda los cambios en tu navegador sin publicar.
</div>

Para cumplir WCAG 1.4.13, el tooltip tiene que:

  • Poder cerrarse con Escape, sin mover el mouse ni el foco.
  • Mantenerse visible mientras el foco o el mouse estén sobre el control.
  • Dejar pasar el mouse sobre el propio tooltip sin desaparecer.

No pongas en un tooltip información imprescindible ni enlaces: en el celular casi nunca se ven.

Pestañas

<div role="tablist" aria-label="Guías por perfil">
  <button type="button" role="tab" id="tab-cm" aria-selected="true" aria-controls="panel-cm">
    Para comunicación
  </button>
  <button type="button" role="tab" id="tab-dev" aria-selected="false" aria-controls="panel-dev" tabindex="-1">
    Para desarrollo
  </button>
</div>
<div role="tabpanel" id="panel-cm" aria-labelledby="tab-cm" tabindex="0">…</div>
<div role="tabpanel" id="panel-dev" aria-labelledby="tab-dev" tabindex="0" hidden>…</div>
  • Tab entra al grupo en la pestaña activa y sale hacia el panel. Solo la pestaña activa tiene tabindex="0".
  • Flecha derecha e izquierda pasan a la pestaña siguiente o anterior; Inicio y Fin, a la primera y la última.
  • Al cambiar de pestaña, se actualizan aria-selected, el tabindex y el panel visible.

Si el contenido de cada pestaña es largo o es una página distinta, mejor usar enlaces comunes: las pestañas sirven para paneles chicos dentro de una misma página.

Carrusel

<section aria-roledescription="carrusel" aria-label="Destacados">
  <button type="button" aria-pressed="false">Pausar</button>
  <button type="button">Diapositiva anterior</button>
  <button type="button">Diapositiva siguiente</button>

  <div aria-live="off">
    <div role="group" aria-roledescription="diapositiva" aria-label="1 de 3">
      <h3>Guía de formularios accesibles</h3>
      <a href="/aprende/formularios">Leer la guía de formularios</a>
    </div>
  </div>
</section>
  • Botón de pausa visible si rota solo (WCAG 2.2.2), y rotación apagada si la persona activó «reducir movimiento».
  • La rotación se detiene cuando el foco o el mouse están dentro del carrusel.
  • aria-live="off" mientras rota solo y "polite" cuando se pasa a mano: si no, el lector de pantalla anuncia cada cambio automático e interrumpe todo.
  • Las diapositivas ocultas no tienen que recibir foco.
  • Texto visible en los botones («Diapositiva anterior»), así el nombre que escucha el lector coincide con lo que se ve.

Muchas veces la mejor solución es no usar carrusel: una lista con lo importante a la vista funciona mejor para todo el mundo.

Casos que confunden

  • aria-haspopup: solo corresponde cuando el botón abre un menú de aplicación, un listado de opciones o un diálogo. Para un desplegable de enlaces, alcanza con aria-expanded.
  • Copiar patrones de una librería: revisá que respeten el teclado. Muchas librerías populares tienen componentes que fallan.
  • Ventanas modales: el patrón está en la guía de patrones de código, con el elemento dialog.

Fuentes y última revisión

Revisado en noviembre de 2026 con la Guía de prácticas de ARIA del W3C (en inglés): patrones de disclosure, acordeón, tooltip, pestañas y carrusel. Para consultar cada atributo, ARIA Hub.

Checklist antes de entregar

Marcá lo que ya resolviste. Abajo ves qué falta y lo podés copiar.

Antes de publicar

0 de 7 puntos cumplidos

Ver lo que falta (7)
  • ¿Usé HTML nativo (button, details, dialog) donde existe?
  • ¿Los menús de navegación son un botón con una lista de enlaces, sin rol menu?
  • ¿Cada control que abre algo actualiza aria-expanded?
  • ¿Los tooltips se cierran con Escape y no tienen información imprescindible?
  • ¿Las pestañas se recorren con flechas y solo la activa tiene tabindex="0"?
  • ¿El carrusel tiene pausa, se detiene con el foco y no anuncia cada cambio automático?
  • ¿Probé cada componente solo con teclado y con un lector de pantalla?