Product Craft Bible
Tables (web)
Inicio Datos y Tablas Tables (web)
Datos y Tablas

Tables (web)

8 reglas W3C WAI Tables Tutorial · WCAG 2.1 SC 1.3.1 Info and Relationships (Nivel A)Pencil & Paper "UX Pattern Analysis: Enterprise Data Tables" · Sebastian De Deyne "Tabular Numbers" · Design with Figma "Designing Data Tables"Jessica Enders / A List Apart "Zebra Striping: Does it Really Help?" (244 participantes; sin mejora estadísticamente significativa en tablas simples) · Pencil & Paper Enterprise Data Tables · Adrian RoselliStanford UIT "Sticky Table Headers" · CSS-Tricks "A Table with a Sticky Header and First Column" · WCAG 2.1.1 Keyboard
75

Tables (web)

8 reglas
648

HTML semántico de tabla: thead, th scope y caption, nunca divs

Las tablas de datos deben construirse con los elementos nativos: <table>, <thead>, <tbody>, <th>, <td> y <caption>. El atributo scope en cada <th> declara si el encabezado aplica a una columna (col) o a una fila (row), permitiendo que el lector de pantalla anuncie el contexto correcto al navegar celda por celda. El <caption> identifica el tema de la tabla y es útil en casi cualquier situación. Una rejilla de <div> con apariencia de tabla pierde por completo la relación programática entre encabezados y datos, lo que viola WCAG 1.3.1 (Info and Relationships) y deja la tabla inutilizable para tecnología asistiva.

W3C WAI Tables Tutorial · WCAG 2.1 SC 1.3.1 Info and Relationships (Nivel A)
Preferir
Ventas por región, Q2 2026
Región Estado
NorteActiva
SurEn revisión
BajíoActiva
Evitar
Región
Estado
Norte
Activa
Sur
En revisión
Sin th, sin scope, sin caption, WCAG 1.3.1 falla
649

Alinea por tipo de dato: texto a la izquierda, números a la derecha con tabular-nums

Cada columna se alinea según la naturaleza de su contenido. El texto y los identificadores (nombres, fechas, códigos, teléfonos) van a la izquierda, porque el ojo occidental está habituado a leer desde ese borde. Las cantidades y porcentajes comparables van a la derecha para que el dígito de mayor peso quede alineado entre filas y la magnitud se compare de un vistazo. El encabezado sigue la alineación de su columna. Además, las columnas numéricas requieren font-variant-numeric: tabular-nums para que cada dígito ocupe el mismo ancho: sin él, una cifra proporcional desplaza los decimales al actualizar y rompe la rejilla vertical de la comparación.

Pencil & Paper "UX Pattern Analysis: Enterprise Data Tables" · Sebastian De Deyne "Tabular Numbers" · Design with Figma "Designing Data Tables"
Preferir
Producto Importe
Suscripción Pro$1,249.00
Almacenamiento$89.50
Soporte 24/7$2,400.00
Dominio$12.99
Evitar
Producto Importe
Suscripción Pro$1,249.00
Almacenamiento$89.50
Soporte 24/7$2,400.00
Dominio$12.99
650

Separadores según densidad: líneas por defecto, zebra en datasets largos, no apiles estados

No existe un separador universalmente óptimo: la elección responde al tamaño del dataset y al número de estados interactivos. Las líneas horizontales de 1px gris claro son el patrón más versátil y funcionan para cualquier tamaño. El zebra striping aporta a lo sumo una mejora marginal de precisión en datasets muy largos, pero introduce ruido cuando la tabla ya tiene varios estados (hover, seleccionado, deshabilitado): apilar zebra sobre tres estados semánticos crea hasta cinco fondos en conflicto y rompe la continuidad visual. Sin separador solo en datasets pequeños donde el espaciado tipográfico ya orienta la lectura. Importante: cambiar display en filas o celdas para lograr el efecto rompe la semántica de tabla en la mayoría de navegadores; el zebra debe lograrse con background, nunca con cambios de display.

Jessica Enders / A List Apart "Zebra Striping: Does it Really Help?" (244 participantes; sin mejora estadísticamente significativa en tablas simples) · Pencil & Paper Enterprise Data Tables · Adrian Roselli
Preferir
ClientePlanMRR
Acme CorpEnterprise$4,200
GlobexPro$890
InitechPro$890
UmbrellaEnterprise$3,750
SoylentStarter$120
HooliEnterprise$5,100
Un único fondo alterno (~4% de tinta). Sin hover ni selección compitiendo: la zebra solo organiza la lectura.
Evitar
ClientePlanMRR
Acme CorpEnterprise$4,200
GlobexPro$890
InitechPro$890
UmbrellaEnterprise$3,750
SoylentStarter$120
HooliEnterprise$5,100
Cinco fondos distintos: zebra par + seleccionado + hover + deshabilitado + base. ¿Cuál fila está activa?
651

Fija el thead con position:sticky al hacer scroll; tabindex="0" en el contenedor

En tablas que superan la altura del viewport, el encabezado debe permanecer visible durante el scroll vertical para que el usuario nunca pierda el contexto de cada columna. El patrón accesible coloca position: sticky; top: 0 en los thead th dentro de un contenedor con overflow-y: auto y altura fija. Es obligatorio añadir tabindex="0" al contenedor para que usuarios de teclado puedan recorrer el área scrollable, con un indicador de foco visible. El antipatrón a evitar es partir el contenido en dos tablas separadas (una para el header fijo, otra para el body con scroll): eso rompe el enlace programático entre encabezado y datos y deja la tabla inservible para lectores de pantalla.

Stanford UIT "Sticky Table Headers" · CSS-Tricks "A Table with a Sticky Header and First Column" · WCAG 2.1.1 Keyboard
Preferir
Haz scroll: el encabezado permanece fijo arriba
Transacciones recientes
FechaConceptoMonto
01 junNómina$48,200
03 junProveedor AWS$3,410
05 junReembolso$120
08 junSuscripción Figma$540
11 junCliente Acme$12,000
14 junRenta oficina$9,800
17 junProveedor AWS$3,410
20 junCliente Globex$6,750
22 junMarketing Ads$2,200
25 junCliente Hooli$15,300
28 junNómina$48,200
30 junImpuestos$21,400
652

Orden activo con aria-sort en el th, button para la acción, indicador no solo por color

Las columnas ordenables usan un <button> dentro del <th> para que la acción sea activable por teclado, y el <th> lleva aria-sort con el valor activo (ascending, descending o none). Solo un encabezado puede tener aria-sort distinto de none al mismo tiempo; tener dos columnas marcadas como ordenadas confunde a la tecnología asistiva. El indicador visual (flecha o chevron) debe cambiar de forma o relleno, no solo de color: una flecha que pasa de contorno hueco a triángulo relleno comunica el orden a usuarios con daltonismo, cumpliendo WCAG 1.4.1 (Use of Color). Una columna ordenada sin señal programática falla WCAG 4.1.2 (Name, Role, Value).

MDN / WAI-ARIA aria-sort · Adrian Roselli "Sortable Table Columns" · WCAG 1.4.1 Use of Color · WCAG 4.1.2 Name, Role, Value
Preferir
Hooli$5,100
Acme Corp$4,200
Umbrella$3,750
Globex$890
Evitar
Cliente
MRR
Hooli$5,100
Acme Corp$4,200
Umbrella$3,750
Globex$890
Sin aria-sort, sin button, orden señalado solo por color
653

Densidad de fila según contexto: compact 32, medium 40, default 48, tall 64px

La altura de fila y el padding determinan cuántos datos caben en pantalla y qué tan cómoda es la lectura. El sistema de IBM Carbon define una escala de densidades confirmada: compact 32px, medium 40px, default 48px y tall 64px (más un nivel condensed de 24px para datos extremos). Compact y medium sirven a herramientas internas con mucha información; default es el uso general; tall facilita lecturas prolongadas o audiencias no técnicas. El padding horizontal mínimo es de 16px por lado, de modo que el espacio entre columnas sume al menos 32px y las celdas nunca se toquen. Ofrecer un selector de densidad y persistir la elección del usuario es práctica recomendada en herramientas enterprise.

IBM Carbon Design System "Data Table" (row heights 24/32/40/48/64px) · Design with Figma "Designing Data Tables" · Pencil & Paper Enterprise Data Tables
Preferir
Compact 32px
SKUStockPrecio
BX-104Disponible$24.00
BX-219Bajo$18.50
Medium 40px
SKUStockPrecio
BX-104Disponible$24.00
BX-219Bajo$18.50
Default 48px
SKUStockPrecio
BX-104Disponible$24.00
BX-219Bajo$18.50
Tall 64px
SKUStockPrecio
BX-104Disponible$24.00
BX-219Bajo$18.50
Evitar
SKUStockPrecio
BX-104Disponible$24.00
BX-219Bajo$18.50
BX-330Agotado$31.20
BX-401Disponible$9.90
24px de alto, 4px de padding: texto y borde casi se tocan
654

Responsive: scroll horizontal con role="region" y primera columna sticky, nunca display:block

En viewports estrechos la estrategia preferida es el scroll horizontal, porque mantiene intacta la semántica de tabla. Se envuelve la <table> en un <div role="region" aria-labelledby="..." tabindex="0"> para que el área scrollable sea anunciada y navegable por teclado, y la primera columna (el identificador) se fija con position: sticky; left: 0 con el background aplicado a nivel de celda. El antipatrón crítico es cambiar el display de la tabla o de las celdas a block o flex para apilarlas: en cuanto se hace eso, la mayoría de los lectores de pantalla dejan de tratarlo como tabla y se pierde toda la asociación encabezado-dato. Si se colapsa a tarjetas, hay que reponer las etiquetas con td::before { content: attr(data-label) }.

Adrian Roselli "A Responsive Accessible Table" · CSS-Tricks "Sticky Header and First Column" · WCAG 1.3.1 Info and Relationships
Preferir
Desliza horizontal: la columna "Cliente" queda fija
Pipeline de cuentas
Cliente Industria Etapa Owner Valor
Acme CorpManufacturaNegociaciónL. Ortiz$48,000
GlobexLogísticaPropuestaM. Díaz$22,500
InitechSoftwareCierreR. Páez$31,000
UmbrellaSaludDescubrimientoL. Ortiz$67,200
Evitar
ClienteAcme Corp
IndustriaManufactura
EtapaNegociación
Valor$48,000
table { display:block }, ya no es una tabla para NVDA ni VoiceOver
655

Celdas con múltiples encabezados: id + headers; scope rowgroup/colgroup en agrupaciones

Cuando una celda de datos se relaciona con más de un encabezado (encabezados de fila y de columna que se cruzan, o subgrupos con un segundo nivel), el atributo scope bidireccional no basta. En ese caso cada <th> recibe un id único y cada <td> lista los ids de todos sus encabezados en headers="id1 id2 id3", separados por espacios. Para tablas con subgrupos de filas o columnas, los encabezados de grupo usan scope="rowgroup" o scope="colgroup". La recomendación de la W3C es que, si la tabla es genuinamente compleja, conviene a todos dividirla en tablas simples separadas con un encabezado descriptivo: es más fácil de entender y de codificar. Sin id+headers en tablas multinivel, la relación encabezado-celda no es determinable programáticamente y WCAG 1.3.1 falla.

W3C WAI Tables Tutorial, Multi-level Headers · W3C WAI Two Headers · WCAG 2.1 SC 1.3.1 Info and Relationships
Preferir
Ventas por región y trimestre
Q1 Q2
Región Norte
Monterrey $120k $138k
Saltillo $74k $81k
Región Sur
Mérida $96k $102k
headers="r1135-norte r1135-mty r1135-q1"
region · ciudad · trimestre, los tres ejes asociados
Evitar
Q1Q2
Región Norte
Monterrey$120k$138k
Saltillo$74k$81k
Región Sur
Mérida$96k$102k
Sin scope="rowgroup", sin id/headers, WCAG 1.3.1 falla