<thead>, <tbody>, <tfoot>
Tablas
Secciones semánticas que agrupan las filas de una tabla según su rol: <thead> contiene los encabezados, <tbody> los datos, <tfoot> el pie (totales o resumen). Mejoran la semántica, la navegación con lectores de pantalla, y el comportamiento al imprimir.
<thead>, <tbody> y <tfoot> son los tres contenedores de secciones de una tabla HTML. En lugar de poner todos los <tr> directamente dentro de <table> sin distinción de roles, estas tres secciones declaran explícitamente qué tipo de filas contiene cada parte: las filas de encabezado van en <thead>, las filas de datos en <tbody>, y las filas de pie (totales, promedios, resúmenes) en <tfoot>.
Ninguna de las tres es estrictamente obligatoria para que una tabla sea HTML válido — podés tener solo <table> con <tr> directos y es perfectamente válido. Pero las secciones aportan dos beneficios concretos que justifican su uso sistemático: semántica explícita que los lectores de pantalla pueden aprovechar para navegar directamente a las partes de la tabla, y el comportamiento de impresión (los navegadores pueden repetir el <thead> en cada página cuando una tabla larga se imprime o se exporta a PDF). Además, hacen el código más legible y mantenible.
Una tabla puede tener exactamente un <thead>, uno o varios <tbody> (para tablas con múltiples grupos de datos), y exactamente un <tfoot>. En la práctica, una sola <tbody> es lo más común. <thead> y <tfoot> son siempre únicos si están presentes.
Cómo funciona
Las secciones se escriben como hijos directos de <table>, en este orden: <caption> (si lo hay), <thead>, uno o más <tbody>, <tfoot>. El orden en el código determina el orden en el DOM, pero en el modelo de tabla el navegador siempre renderiza el <tfoot> al final visualmente, aunque en el HTML esté antes de <tbody>. Históricamente se lo podía escribir antes que <tbody> para que se descargara antes de los datos y el navegador pudiera reservar espacio; hoy esa razón ya no aplica y es más claro escribirlos en orden lógico.
Dentro de cada sección van los <tr> correspondientes.
<table>
<caption>Ventas por mes — primer semestre</caption>
<thead>
<tr>
<th scope="col">Mes</th>
<th scope="col">Ventas</th>
<th scope="col">Meta</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Enero</th>
<td>1.200</td>
<td>1.000</td>
</tr>
<tr>
<th scope="row">Febrero</th>
<td>980</td>
<td>1.000</td>
</tr>
<tr>
<th scope="row">Marzo</th>
<td>1.450</td>
<td>1.200</td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row">Total</th>
<td>3.630</td>
<td>3.200</td>
</tr>
</tfoot>
</table>
| Mes | Ventas | Meta |
|---|---|---|
| Enero | 1.200 | 1.000 |
| Febrero | 980 | 1.000 |
| Marzo | 1.450 | 1.200 |
| Total | 3.630 | 3.200 |
Modelo de contenido
Cada sección solo puede contener <tr> (y, implícitamente, el modelo de contenido de tabla). Display por defecto: table-header-group (<thead>), table-row-group (<tbody>), table-footer-group (<tfoot>).
Atributos
Las tres secciones no tienen atributos propios de uso moderno. Sus atributos históricos (align, valign, char, charoff, bgcolor) son todos legacy — reemplazados por CSS.
Cuándo usar qué
| Sección | Contiene | Cuándo incluirla |
|---|---|---|
<thead> | Filas de encabezado (con <th scope="col">) | Siempre que la tabla tenga encabezados de columna |
<tbody> | Filas de datos | Siempre — aunque solo una |
<tfoot> | Filas de totales, promedios o resumen | Solo si la tabla tiene datos agregados |
Una tabla sin <thead> ni <tbody> (solo <table> con <tr>) es válida, pero el navegador inserta un <tbody> implícito en el DOM. Es más claro escribirlo explícito.
Accesibilidad
<thead> tiene el rol rowgroup en el árbol de accesibilidad, con el subtipo “encabezado de tabla”. <tbody> y <tfoot> tienen el rol rowgroup genérico. Los lectores de pantalla más modernos (NVDA + Firefox, VoiceOver + Safari) permiten saltar directamente al <tbody> para ir al cuerpo de datos sin pasar por los encabezados. Sin secciones, la navegación es celda a celda desde el principio.
Notas, gotchas e interacción
<tbody>se inserta implícitamente si no lo escribís. El DOM siempre tendrá un<tbody>aunque el HTML no lo tenga. Selectores CSS comotable > trpueden no funcionar porque en el DOM ese<tr>está dentro de<tbody>, no directo en<table>.<tfoot>puede ir antes de<tbody>en el HTML. Es válido pero confuso — preferí el orden lógico:thead→tbody→tfoot.<thead>en impresión: si la tabla es larga y el usuario la imprime, los navegadores pueden repetir el<thead>en cada página automáticamente (aunque el soporte varía). Es el beneficio más tangible de usar<thead>explícito.- Varios
<tbody>: son válidos para agrupar filas con distintos roles o categorías. Cada<tbody>puede tener su propia<tr>inicial de subencabezado con<th colspan>si se quiere.
Vigente / legacy
Las tres secciones son completamente vigentes. Sus atributos de presentación son todos legacy desde HTML5.
Aprendelo en el recorrido
Esta entrada complementa la lección La tabla semántica del módulo Tablas, donde <thead>, <tbody> y <tfoot> se practican como secciones de la tabla completa con encabezados, datos y totales.