Addaw, ir a inicio Donar

Lección 8 de 10 · 17 min de lectura · Revisado el 26/10/2026

Carruseles, tablas interactivas y arrastrar y soltar (2.5.7)

Esta lección reúne tres componentes que combinan movimiento, densidad de información y gestos: los carruseles de la portada, las tablas con ordenación y filtros, y las interfaces de arrastrar y soltar. Son los que más criterios distintos tocan a la vez: tiempo y movimiento (2.2.2 Poner en pausa, detener, ocultar), teclado (2.1.1), nombre y estado (4.1.2), gestos (2.5.1 Gestos del puntero, 2.5.7 Movimientos de arrastre) y tamaño del objetivo (2.5.8).

Carruseles

Los carruseles automáticos son uno de los componentes peor valorados en los estudios de usabilidad y una fuente constante de incumplimientos. Si el equipo de diseño insiste, el patrón Carousel de la APG (se abre en una ventana nueva) marca el mínimo:

  • Contenedor con role="region" (o <section>), aria-roledescription="carrusel" y un nombre con aria-label («Noticias destacadas»).
  • Control de pausa como primer elemento enfocable, con aria-pressed o texto alternante («Pausar la rotación» / «Reanudar la rotación»). Es obligatorio por 2.2.2 si el movimiento dura más de 5 segundos y es automático. Además, la rotación debe detenerse mientras el puntero o el foco estén dentro del carrusel.
  • Botones anterior y siguiente con nombre («Diapositiva anterior», «Diapositiva siguiente»), de al menos 24 por 24 píxeles CSS.
  • Cada diapositiva en un contenedor con role="group", aria-roledescription="diapositiva" y nombre («2 de 5» o el título de la noticia).
  • Indicadores de posición (los puntos) como botones con nombre («Ir a la diapositiva 3») o como pestañas si siguen el patrón tablist.
  • Diapositivas no visibles ocultas al árbol (aria-hidden="true" o hidden) y sin elementos enfocables, para que Tab no recorra enlaces invisibles.
  • Anuncio de cambios: si la persona pulsa «siguiente», la región de diapositivas puede llevar aria-live="polite" mientras la rotación automática esté parada, y aria-live="off" mientras gire sola, para no interrumpir cada pocos segundos.

Ejemplo

<section aria-roledescription="carrusel" aria-label="Noticias destacadas">
  <button type="button" aria-pressed="false">Pausar la rotación</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">…</div>
    <div role="group" aria-roledescription="diapositiva" aria-label="2 de 3" hidden>…</div>
    <div role="group" aria-roledescription="diapositiva" aria-label="3 de 3" hidden>…</div>
  </div>
</section>

Y respeta prefers-reduced-motion: si la persona ha pedido menos movimiento en su sistema, el carrusel no debe girar solo (lo veremos en el curso de CSS).

La alternativa más accesible, y a menudo más eficaz, es no rotar: una rejilla estática con las tres noticias.

Tablas interactivas

Sobre la base de la tabla de datos accesible del primer curso, las tablas con ordenación, filtros y acciones por fila añaden requisitos:

  • Ordenación: el control de ordenar debe ser un <button> dentro del <th>, con nombre («Ordenar por fecha») y, en el <th>, aria-sort="ascending|descending|none" actualizado. Al reordenar, anuncia el resultado en una región de estado («Ordenado por fecha, de más reciente a más antigua»).
  • Acciones por fila: cada botón necesita un nombre que identifique la fila («Editar el expediente 2024/0123»), porque fuera de contexto «Editar» repetido veinte veces no sirve. Puede hacerse con texto oculto accesiblemente o con aria-labelledby combinando el texto del botón y la celda identificadora.
  • Selección de filas: casillas de verificación nativas con etiqueta («Seleccionar el expediente 2024/0123») y una casilla de cabecera «Seleccionar todo» que refleje el estado mixto con indeterminate.
  • Paginación y filtros: anuncia en una región de estado el número de resultados tras cada cambio; la paginación es una <nav aria-label="Paginación"> con enlaces o botones y aria-current="page" en la página actual.
  • Rejillas editables (hoja de cálculo): solo entonces el rol grid de la APG, con navegación por celdas con flechas y una sola parada de Tab. Para una tabla que se lee, aunque tenga botones, <table> normal es lo correcto. Verás el patrón grid a fondo en la lección siguiente.

Error frecuente

Hacer clicable toda la fila (<tr onclick>) para abrir el detalle, sin ningún enlace ni botón dentro. No es alcanzable con teclado ni tiene rol ni nombre. Pon un enlace real en la celda principal (el identificador o el título) y, si quieres, amplía su área clicable con CSS; la fila entera como objetivo es un extra para el ratón, nunca el único camino.

Arrastrar y soltar y 2.5.7

WCAG 2.2 añadió el criterio 2.5.7 Movimientos de arrastre (AA): toda funcionalidad que use un movimiento de arrastre debe poder realizarse con un único puntero sin arrastrar (es decir, con clics o toques), salvo que el arrastre sea esencial o lo determine el agente de usuario. Afecta a reordenar listas, mover tarjetas entre columnas (tableros kanban), deslizadores, recortar imágenes, ordenar prioridades y mover elementos en un mapa.

Fíjate en que 2.5.7 habla de puntero, no de teclado: la alternativa de teclado es exigible por 2.1.1, pero además hace falta una alternativa de puntero sin arrastre, porque muchas personas con temblor, poca fuerza o que usan un lápiz o un ratón de cabeza pueden hacer clic pero no mantener pulsado mientras mueven con precisión.

Ejemplo

Lista de prioridades reordenable. Además del arrastre, cada elemento ofrece botones de mover:

<ul aria-label="Orden de prioridad">
  <li>
    Renovar el DNI
    <button type="button" aria-label="Subir Renovar el DNI">↑</button>
    <button type="button" aria-label="Bajar Renovar el DNI">↓</button>
  </li>
  …
</ul>
<p role="status"></p>

Tras cada movimiento se anuncia «Renovar el DNI movido a la posición 2 de 4» en la región de estado y el foco permanece en el botón pulsado (que ahora está en la nueva posición; si el script mueve el elemento en el DOM, vuelve a llamar a focus() sobre el botón, porque el navegador puede perderlo). Otras alternativas conformes: un menú «Mover a…» con destinos, un campo numérico de posición, o seleccionar el elemento y después pulsar el destino (dos clics).

Para los deslizadores, el <input type="range"> nativo cumple de serie: admite clic en cualquier punto de la pista y flechas con teclado. Las excepciones de 2.5.7 son estrechas: dibujar a mano alzada es esencial; reordenar una lista, no.

Punto clave

Carrusel: pausa, botones con nombre, diapositivas ocultas al árbol y sin rotación si la persona prefiere menos movimiento. Tabla interactiva: botones de ordenar con aria-sort, nombres de acción que identifican la fila, anuncios de estado. Arrastre: siempre una alternativa de clics o botones (2.5.7) y de teclado (2.1.1).

Cómo comprobarlo

  • Carga la página y espera: si algo se mueve más de 5 segundos sin control de pausa accesible con teclado, falla 2.2.2.
  • Tabula por el carrusel: no deben aparecer paradas en diapositivas invisibles.
  • En la tabla, ordena con teclado y escucha el anuncio; abre la lista de botones del lector y verifica que cada acción identifica su fila.
  • Intenta cada operación de arrastre solo con clics y solo con teclado; si alguna es imposible, falla 2.5.7 o 2.1.1.
  • Mide los botones pequeños de los carruseles y las tablas: 24 por 24 píxeles CSS o separación equivalente (2.5.8).

Resumen

  • Un carrusel automático necesita control de pausa (2.2.2), botones con nombre, diapositivas ocultas al árbol y respeto a prefers-reduced-motion; la rejilla estática suele ser mejor.
  • En tablas interactivas, los botones de ordenar llevan aria-sort, las acciones de fila identifican la fila y los cambios se anuncian con role="status".
  • Una fila clicable sin enlace ni botón dentro es inaccesible; el enlace real va en la celda principal.
  • 2.5.7 exige una alternativa de puntero sin arrastre (clics, botones, menú «Mover a») para toda función de arrastrar y soltar no esencial, además del teclado.
  • Los objetivos de estos componentes deben medir al menos 24 por 24 píxeles CSS (2.5.8).

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.