4 de noviembre de 2026
Tablas de datos accesibles HTML: th, scope, headers y caption con ejemplos de código
Las tablas de datos accesibles en HTML se basan en un principio sencillo: cada celda de encabezado se marca con <th>, cada celda de datos con <td>, y el marcado define la relación entre ambas; en las tablas más complejas pueden ser necesarias asociaciones explícitas. Es lo que recuerda el tutorial de tablas del W3C (WAI): las tecnologías de apoyo se basan en ese marcado para dar contexto al usuario. Según la complejidad de la tabla, añadirá el atributo scope, o los atributos id y headers, y, en la mayoría de los casos, un elemento <caption> que da título a la tabla. Esta guía recorre cada caso con código que puede adaptar: tabla con un solo encabezado, tabla con encabezados de fila y de columna, encabezados que abarcan varias celdas, tabla compleja de varios niveles, título y resumen, y los errores que conviene evitar.
Por qué el marcado es clave en las tablas de datos accesibles HTML
Una tabla sin marcado estructural, que no diferencia las celdas de encabezado de las de datos ni las relaciona correctamente, crea barreras de accesibilidad. Confiar solo en las pistas visuales no basta: los encabezados y los datos tienen que poder determinarse mediante software.
En la práctica, un lector de pantalla lee una celda cada vez y anuncia los encabezados de fila y de columna asociados, de modo que el usuario no pierde el contexto al recorrer la tabla. Otras personas muestran los datos de otra forma, por ejemplo con hojas de estilo personalizadas que destacan los encabezados, cambian el tamaño del texto y los colores o presentan la información como listas en lugar de cuadrículas. Estas presentaciones alternativas solo funcionan si el código de la tabla está bien estructurado.
En cuanto a las WCAG, el tutorial del W3C vincula estas prácticas al criterio de conformidad 1.3.1 Información y relaciones (nivel A) y a las técnicas H51 (usar marcado de tabla para presentar información tabular), H63 (usar el atributo scope para asociar celdas de encabezado con celdas de datos en tablas de datos) y H39 (usar el elemento caption para asociar un título a una tabla de datos).
- Celdas de encabezado: <th>.
- Celdas de datos: <td>.
- Tablas más complejas: pueden necesitar asociaciones explícitas con scope, id y headers.
- Estas reglas se aplican a tablas de datos, no a tablas de maquetación.
Tabla sencilla: <th> para los encabezados y scope para evitar ambigüedades
El caso más simple es una tabla con un único encabezado, en la primera fila o en la primera columna, y datos claramente distintos de una columna a otra. Para una pequeña tabla de conciertos (fecha, evento, lugar), marcar la primera fila con <th> y el resto con <td> solo es aceptable porque la tabla es muy pequeña y los datos de cada columna son claramente distintos, lo que hace evidente la relación entre encabezados y datos. Aun así, el W3C advierte que algunos lectores de pantalla leerán «Date – Event – Venue» en la celda «Venue», porque la dirección de los <th> es ambigua.
En cuanto los datos dejan de distinguirse por sí solos, añada el atributo scope. En el ejemplo del W3C, una lista de coleccionistas con apellido, nombre y ciudad, es imposible distinguir un apellido de un nombre o de una ciudad sin saber a qué encabezado corresponde cada celda. El valor col de scope define la dirección de los encabezados y los asocia con las celdas de datos de su columna. El W3C precisa que scope también es necesario en tablas más grandes con una sola fila o columna de encabezados.
<table>
<caption>Coleccionistas de osos de peluche</caption>
<tr>
<th scope="col">Apellido</th>
<th scope="col">Nombre</th>
<th scope="col">Ciudad</th>
</tr>
<tr>
<td>Phoenix</td>
<td>Imari</td>
<td>Henry</td>
</tr>
[…]
</table>Encabezados de fila y de columna: scope="col" y scope="row"
Cuando una tabla tiene a la vez encabezado de columnas y encabezado de filas, la relación entre encabezados y datos se vuelve ambigua enseguida. Use <th> para todas las celdas de encabezado y declare la dirección de cada una: scope="col" indica que el encabezado se aplica a toda la columna; scope="row", a toda la fila.
El ejemplo del W3C es una tabla de franjas de entrega: los días de la semana arriba, las franjas horarias a la izquierda y, en las celdas, «Abierto» o «Cerrado». Esas indicaciones solo tienen sentido si se pueden vincular a un día y una hora concretos. La celda vacía de arriba a la izquierda sigue siendo un <td>.
La misma técnica sirve cuando los encabezados de fila no están en la primera columna. En una tabla de vacaciones en la que la primera columna contiene un identificador y la segunda el nombre de la persona, el nombre se marca con <th scope="row"> y se aplica así a las celdas situadas a su izquierda y a su derecha.
<table>
<caption>Franjas de entrega</caption>
<tr>
<td></td>
<th scope="col">Lunes</th>
<th scope="col">Martes</th>
</tr>
<tr>
<th scope="row">09:00 – 11:00</th>
<td>Cerrado</td>
<td>Abierto</td>
</tr>
[…]
</table>Encabezados combinados: colgroup, rowgroup, thead y tbody
Cuando una celda de encabezado abarca varias columnas (colspan) o varias filas (rowspan), debe asociarse con las celdas correspondientes del grupo mediante scope="colgroup" o scope="rowgroup". Pero antes hay que definir la estructura de esos grupos en el marcado.
Para las columnas, cada una se identifica con un elemento <col>, empezando por la izquierda; si un encabezado abarca varias columnas, un <colgroup> con atributo span sustituye a ese número de elementos <col>. La suma de los <col> que no están dentro de un <colgroup> y de las columnas indicadas por los span de los <colgroup> debe ser igual al número total de columnas de la tabla. Para las filas, un grupo se define con <thead>, <tbody> o <tfoot>.
- <thead> y <tfoot> pueden usarse una vez por tabla.
- Una tabla puede tener cualquier número de <tbody>, cada uno de los cuales define un grupo de filas.
- Si un encabezado abarca varias filas de encabezado, esas filas se agrupan en <thead> en lugar de <tbody>; si abarca varias filas en el pie de la tabla, se usa <tfoot>.
- El W3C señala que usar <thead>, <tbody> y <tfoot> en todas las tablas puede evitar dudas sobre cuándo emplearlos.
<table>
<col>
<colgroup span="2"></colgroup>
<colgroup span="2"></colgroup>
<tr>
<td rowspan="2"></td>
<th colspan="2" scope="colgroup">Marte</th>
<th colspan="2" scope="colgroup">Venus</th>
</tr>
<tr>
<th scope="col">Fabricados</th>
<th scope="col">Vendidos</th>
<th scope="col">Fabricados</th>
<th scope="col">Vendidos</th>
</tr>
<tr>
<th scope="row">Osos de peluche</th>
<td>50.000</td>
<td>30.000</td>
<td>100.000</td>
<td>80.000</td>
</tr>
[…]
</table>Tabla compleja: vincular cada celda con headers e id
Algunas tablas son demasiado complejas para asociar encabezados y datos de forma estrictamente horizontal o vertical. El W3C menciona dos casos: tablas cuyos encabezados de columna se repiten o cambian a mitad de la tabla, y tablas en las que cada celda de datos se asocia con tres o más encabezados.
El método: cada <th> recibe un id único en todo el documento y cada <td> enumera en su atributo headers el id o los id de los encabezados que le corresponden, separados por espacios. En el ejemplo del W3C sobre disponibilidad de alojamiento vacacional, la celda «11» queda vinculada a la vez a la ciudad (París), al número de dormitorios (1 dormitorio) y al tipo de alojamiento (estudio).
Un truco del tutorial: en una tabla de contactos de proveedores cuyos encabezados cambian a mitad de la tabla, las propias celdas de encabezado apuntan a una celda vacía con el id «blank», lo que impide que algunas tecnologías de apoyo lean un encabezado para esas celdas de encabezado.
Antes de lanzarse, pregúntese si la tabla necesita realmente ser tan compleja. El W3C sugiere que en muchos casos merece la pena dividirla en tablas más pequeñas: la información resulta más fácil de entender para todos y más fácil de programar, y las tablas sencillas tienen mucho mejor soporte en las herramientas de creación de contenido, incluidos los editores WYSIWYG.
[…]
<tr>
<th id="par" colspan="5" scope="colgroup">París</th>
</tr>
<tr>
<th id="pbed1">1 dormitorio</th>
<td headers="par pbed1 stud">11</td>
<td headers="par pbed1 apt">20</td>
[…]
</tr>Título con <caption> y resumen de las tablas complejas
El título funciona como un encabezado de la tabla. La mayoría de los lectores de pantalla lo anuncian; ayuda al usuario a encontrar la tabla, entender de qué trata y decidir si quiere leerla. Para quienes navegan en «modo tablas», saltando de tabla en tabla, el título es el principal medio para identificarlas. Se codifica con el elemento <caption>, situado directamente como hijo de <table>, y debe ser un encabezado breve, como «Conciertos».
El resumen describe cómo se organizan los datos y ayuda a navegar; normalmente solo hace falta en tablas complejas. Si proporciona ambos, el resumen no debe repetir información que ya figure en el título. El W3C recuerda que título y resumen no son obligatorios en todos los casos para cumplir las WCAG, pero son formas bastante sencillas de aportar una información que a menudo se necesita.
- Resumen dentro de <caption>: el texto sigue al título, por ejemplo en un <span>, y también es visible para los usuarios que ven la pantalla.
- Resumen vinculado con aria-describedby en <table>, que apunta a cualquier elemento con un id único, por ejemplo un párrafo. Ese elemento no tiene por qué estar delante de la tabla, pero situarlo cerca ayuda a descubrir el resumen antes, sobre todo a quienes no usan lector de pantalla. El W3C advierte que esta función WAI-ARIA puede tener menos soporte en las tecnologías de apoyo.
- Tabla dentro de <figure> con <figcaption>: en «modo tablas», los usuarios de lectores de pantalla no suelen poder identificar la tabla por un título colocado así. La parte del título de <figcaption> puede asociarse explícitamente a la tabla con aria-labelledby y la del resumen con aria-describedby, lo que puede hacer que título y resumen se lean varias veces. El W3C advierte también que esta función HTML5 puede tener menos soporte en las tecnologías de apoyo.
<table>
<caption>Disponibilidad de alojamiento vacacional<br>
<span>La primera columna indica la ciudad y el tamaño del alojamiento; las demás, el tipo y el número de alojamientos disponibles</span>
</caption>
[…]
</table>Qué no hacer en una tabla de datos HTML
La página «Tips and Tricks» del tutorial reúne varias prácticas que conviene evitar.
- Dar estilo a celdas <td> para que parezcan encabezados: use <th>; si no, la tabla será menos accesible, o incluso inaccesible. También es útil diferenciar visualmente <th> y <td>.
- Juntar varias tablas en una añadiendo una fila extra de <th>: los lectores de pantalla pueden leer todas las celdas <th> de una columna. Empiece un nuevo <table> cuando cambie el tema.
- Poner los encabezados en una columna y todos los datos en una segunda: cada dato necesita su propia celda.
- Crear pseudofilas con <br>: los datos de las pseudofilas pueden dejar de estar bien alineados cuando se cambia el tamaño del texto.
- Recortar la tabla en pantallas pequeñas o con zoom, por ejemplo con overflow: hidden en CSS. El tutorial aplica overflow: scroll a un elemento que envuelve la tabla, pero hay muchas otras opciones de visualización.
- Perder la estructura en el diseño adaptable: la relación entre encabezados y datos debe estar disponible en todos los formatos.
- Usar tablas para maquetar: use CSS. Si ya existen tablas de maquetación, no utilice en ellas ni los elementos estructurales (como <th> o <caption>) ni los atributos tratados en el tutorial (scope, headers…), y añada role="presentation" al elemento <table>.
Preguntas frecuentes
¿Cómo hacer accesible una tabla HTML?
Marque las celdas de encabezado con <th> y las de datos con <td>. Añada scope="col" o scope="row" cuando la dirección de los encabezados sea ambigua, scope="colgroup" o scope="rowgroup" para encabezados combinados, e id y headers cuando la asociación no pueda ser estrictamente horizontal o vertical (encabezados que cambian a mitad de tabla, tres o más encabezados por celda). En la mayoría de los casos, dé también un título a la tabla con <caption>: las WCAG no lo exigen en todos los casos, pero resulta útil.
¿Qué diferencia hay entre scope y headers?
scope indica la dirección de un encabezado: col, row, colgroup o rowgroup. Basta mientras la asociación sea estrictamente horizontal o vertical. headers, colocado por lo general en una celda de datos, enumera explícitamente los id de los encabezados asociados; se usa cuando los encabezados cambian a mitad de la tabla o cuando tres o más encabezados afectan a cada celda.
¿Es obligatorio el elemento caption en una tabla?
Según el W3C, título y resumen no son obligatorios en todos los casos para cumplir las WCAG. Aun así, el título es útil en la mayoría de las situaciones: la mayoría de los lectores de pantalla lo anuncian y es el principal medio para identificar una tabla en modo tablas.
¿Hay que poner scope en una tabla sencilla?
No siempre: los <th> sin scope solo son aceptables en una tabla pequeña cuyos datos se distinguen claramente en cada columna; aun así, algunos lectores de pantalla leerán «Date – Event – Venue» en la celda «Venue», porque la dirección de los <th> es ambigua. En cuanto los datos son ambiguos, o en una tabla más grande con una sola fila o columna de encabezados, añada scope.
¿Se puede usar una tabla HTML para maquetar?
No, el W3C recomienda CSS para la maquetación. En una tabla de maquetación ya existente, no utilice ni elementos estructurales como <th> o <caption> ni los atributos vistos en esta guía (scope, headers…), y añada role="presentation" al elemento <table>.
Más sobre el tema en Conformly
Fuentes
Este artículo se basa en las fuentes oficiales citadas al final de la página.