Acordeón y pestañas accesibles en JavaScript: código para copiar y pegar | We.Inc
Un acordeón en JavaScript puro con altura animada y aria-expanded, y pestañas con teclas de flecha y roving tabindex. Ambos funcionan en vivo en la página, con un checklist de teclado y una tabla ARIA.
Un acordeón accesible usa un botón real dentro de cada encabezado, con aria-expanded indicando si su panel está abierto y aria-controls nombrando el panel. Las pestañas accesibles usan role=tablist, tab y tabpanel, con aria-selected, y se recorren con las teclas de flecha, dejando solo la pestaña seleccionada en el orden de Tab. Las dos demos de abajo funcionan en vivo.
Cuál usar
Usa
Cuándo
Acordeón
Páginas largas de preguntas, donde la gente puede leer varias respuestas
Pestañas
Unas pocas vistas de lo mismo, que se leen de una en una
details y summary
Mostrar y ocultar de forma sencilla sin nada de JavaScript
Cada demo es un único bloque autónomo de HTML, CSS y JavaScript. Edítalo y el resultado se vuelve a ejecutar. Después aparta el ratón y pruébalo con el teclado usando el checklist de más abajo.
Copia en tu página el bloque del componente que necesitas.
Cambia el texto, manteniendo cada id único en la página.
Prueba con el teclado: Tab, Enter, Space, las flechas, Home y End.
Prueba con un lector de pantalla: debería decir expandido o contraído, o pestaña 2 de 3.
Revisa la página con el movimiento reducido activado; los paneles deberían abrirse sin animación.
Mantén el botón dentro del encabezado en lugar de hacer clicable el encabezado; los encabezados no reciben el foco ni anuncian su estado.
Usa el atributo hidden en los paneles cerrados para que no se pueda llegar a sus enlaces con Tab.
No pongas pestañas dentro de pestañas ni acordeones dentro de pestañas; la gente pierde la noción de dónde está.
Si las respuestas importan para el SEO, déjalas en el HTML (ocultas, no cargadas después) para que los rastreadores y las personas vean el mismo texto.
Preguntas frecuentes
¿Las pestañas deben cambiar con las flechas o con Enter?
La guía de ARIA permite las dos cosas. Cambiar a medida que se mueve la flecha (activación automática) resulta lo más rápido cuando los paneles ya están cargados. Si mostrar un panel es lento, mueve el foco con las flechas y cambia con Enter o Space.
¿Cómo animo la altura de un acordeón sin medirla con JavaScript?
Convierte el panel en una cuadrícula y haz una transición de grid-template-rows de 0fr a 1fr, con un elemento interior que tenga overflow hidden. El navegador calcula la altura por ti.
¿Es accesible un elemento details?
Sí. Los navegadores exponen summary como un botón con estado expandido, y funciona con el teclado sin hacer nada. Estilizar el marcador y animarlo es más difícil, por eso muchos sitios siguen creando el suyo propio.
¿Cuentan para el SEO las respuestas ocultas de un acordeón?
El contenido que está en el HTML pero contraído se sigue rastreando. Mantenlo en el código fuente de la página en lugar de cargarlo al hacer clic, y asegúrate de que la respuesta visible coincide con lo que hay en el HTML.
Siguientes pasos
Si trabajas con React, nuestra galería de componentes tiene un conjunto de pestañas con subrayado deslizante y un acordeón de preguntas frecuentes, ambos con JSX para copiar. Para una sección de preguntas frecuentes, añade datos estructurados FAQPage equivalentes solo si las preguntas y respuestas se ven en la página.
Errores habituales
Usar elementos div con manejadores de clic como encabezados del acordeón. No se puede llegar a ellos con Tab y los lectores de pantalla no saben que hacen algo.
Poner todas las pestañas en el orden de Tab, lo que obliga a los usuarios de teclado a recorrerlas todas para llegar al contenido.
Olvidar actualizar aria-expanded o aria-selected cuando cambia el estado, de modo que el lector de pantalla anuncia algo incorrecto.
Acordeón
Acordeón accesible con altura animada
Cada encabezado contiene un botón real con aria-expanded y aria-controls. La altura se anima con una transición de filas de grid, así que no hay que medir scrollHeight. Pruébalo con Tab, Enter y Space.
Solo un panel abierto a la vez
Cuando se abre un panel, cierra cualquier otro que esté abierto. Que sea opcional: quien compara dos respuestas a menudo quiere tener ambas abiertas.
Alternativa sin JavaScript: details y summary
Los elementos details nativos se abren y cierran sin script. Darles el mismo atributo name los hace excluyentes en los navegadores actuales; los antiguos simplemente permiten varios abiertos.
Pestañas
Pestañas con roving tabindex y teclas de flecha
Solo la pestaña seleccionada tiene tabindex 0, así que Tab entra una vez en la lista de pestañas y luego pasa al panel. Las flechas izquierda y derecha se mueven entre pestañas, Home y End saltan a los extremos.
Checklist de teclado y ARIA
Prueba de teclado: prueba cada una en las demos
Tecla
Acordeón
Pestañas
Tab
Pasa al siguiente botón de encabezado
Entra en la lista de pestañas por la pestaña seleccionada y luego pasa al panel
Shift + Tab
Vuelve al botón de encabezado anterior
Sale de la lista de pestañas hacia atrás
Enter o Space
Abre o cierra el panel con el foco
Selecciona la pestaña con el foco (solo necesario con activación manual)
Flecha derecha / izquierda
No es necesario
Pestaña siguiente / anterior, volviendo al principio
Home / End
Opcional: primer / último encabezado
Primera / última pestaña
Referencia ARIA
Atributos que necesita cada parte
Elemento
Acordeón
Pestañas
Disparador
button dentro de un encabezado, aria-expanded, aria-controls
role=tab, aria-selected, aria-controls, tabindex 0 o -1
Contenedor
No necesita nada
role=tablist con aria-label
Panel
id; role=region con aria-labelledby es opcional
role=tabpanel, aria-labelledby, tabindex 0 si no tiene contenido que pueda recibir el foco