Table
Pattern de tabla de datos con cabecera, acciones, filtros, ordenación y alineación configurable.
1. Tabla base
Título de tabla sencilla
Descripción de la tabla
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
Mostrar HTML
<div class="gn-table">
<div class="gn-table__label">
<div class="gn-table__label-copy">
<h4 class="gn-table__title" id="table-base-title">Título de tabla sencilla</h4>
<p class="gn-field__hint gn-table__hint">Descripción de la tabla</p>
</div>
</div>
<div class="gn-table__container">
<table class="gn-table__element" aria-labelledby="table-base-title">
<caption class="sr-only">Tabla base con tres columnas</caption>
<thead>
<tr>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado izquierda">
<span class="gn-table__th-text">Encabezado izquierda</span>
</button>
</th>
<th class="gn-table__th gn-table__th--center" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado centrado">
<span class="gn-table__th-text">Encabezado centrado</span>
</button>
</th>
<th class="gn-table__th gn-table__th--right" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado derecha">
<span class="gn-table__th-text">Encabezado derecha</span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
</tbody>
</table>
</div>
</div>
2. Tabla base — variante compacta
Título de tabla sencilla compacta
Descripción de la tabla
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
| Dato izquierda | Dato centrado | Dato derecha |
Mostrar HTML
<div class="gn-table gn-table--compact">
<div class="gn-table__label">
<div class="gn-table__label-copy">
<h4 class="gn-table__title" id="table-compact-title">Título de tabla sencilla compacta</h4>
<p class="gn-field__hint gn-table__hint">Descripción de la tabla</p>
</div>
</div>
<div class="gn-table__container">
<table class="gn-table__element" aria-labelledby="table-compact-title">
<caption class="sr-only">Tabla compacta con tres columnas</caption>
<thead>
<tr>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado izquierda">
<span class="gn-table__th-text">Encabezado izquierda</span>
</button>
</th>
<th class="gn-table__th gn-table__th--center" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado centrado">
<span class="gn-table__th-text">Encabezado centrado</span>
</button>
</th>
<th class="gn-table__th gn-table__th--right" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado derecha">
<span class="gn-table__th-text">Encabezado derecha</span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td">Dato izquierda</td>
<td class="gn-table__td gn-table__td--center">Dato centrado</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
</tbody>
</table>
</div>
</div>
3. Celdas con icono y datos secundarios
Título de tabla sencilla
Descripción de la tabla
| Tipo | |||
|---|---|---|---|
|
Nombre de la persona
NIF 00000000A
|
Un dato muy largo que posiblemente ocupe varias líneas | Dato derecha | |
|
Nombre de la persona
NIF 00000000B
|
Un dato muy largo que posiblemente ocupe varias líneas | Dato derecha | |
|
Nombre de la persona
NIF 00000000C
|
Un dato muy largo que posiblemente ocupe varias líneas | Dato derecha |
Mostrar HTML
<div class="gn-table">
<div class="gn-table__label">
<div class="gn-table__label-copy">
<h4 class="gn-table__title" id="table-icon-title">Título de tabla sencilla</h4>
<p class="gn-field__hint gn-table__hint">Descripción de la tabla</p>
</div>
</div>
<div class="gn-table__container">
<table class="gn-table__element" aria-labelledby="table-icon-title">
<caption class="sr-only">Tabla con columna de iconos y datos secundarios</caption>
<thead>
<tr>
<th class="gn-table__th gn-table__th--no-sort gn-table__th--icon" scope="col">
<span class="sr-only">Tipo</span>
</th>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
<th class="gn-table__th gn-table__th--right" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="gn-table__td gn-table__td--icon">
<svg class="gn-table__td-icon" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
</td>
<td class="gn-table__td">
<div class="gn-table__td-group">
<span>Nombre de la persona</span>
<span class="gn-table__td-secondary">NIF 00000000A</span>
</div>
</td>
<td class="gn-table__td">Un dato muy largo que posiblemente ocupe varias líneas</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td gn-table__td--icon">
<svg class="gn-table__td-icon" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
</td>
<td class="gn-table__td">
<div class="gn-table__td-group">
<span>Nombre de la persona</span>
<span class="gn-table__td-secondary">NIF 00000000B</span>
</div>
</td>
<td class="gn-table__td">Un dato muy largo que posiblemente ocupe varias líneas</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
<tr>
<td class="gn-table__td gn-table__td--icon">
<svg class="gn-table__td-icon" aria-hidden="true" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
</td>
<td class="gn-table__td">
<div class="gn-table__td-group">
<span>Nombre de la persona</span>
<span class="gn-table__td-secondary">NIF 00000000C</span>
</div>
</td>
<td class="gn-table__td">Un dato muy largo que posiblemente ocupe varias líneas</td>
<td class="gn-table__td gn-table__td--right">Dato derecha</td>
</tr>
</tbody>
</table>
</div>
</div>
4. Tabla ordenable con hover — estado de foco en cabecera
Los encabezados ordenables usan <button> para recibir foco. Al pulsar Tab sobre el encabezado se muestra el anillo de foco del sistema.
Tabla ordenable con hover
Hint descriptivo
| Dato | Dato | Dato |
| Dato | Dato | Dato |
| Dato | Dato | Dato |
| Dato | Dato | Dato |
| Dato | Dato | Dato |
Mostrar HTML
<div class="gn-table" data-gn-table-hover data-gn-table-sort-demo>
<div class="gn-table__label">
<div class="gn-table__label-copy">
<h4 class="gn-table__title" id="table-sortable-title">Tabla ordenable con hover</h4>
<p class="gn-field__hint gn-table__hint">Hint descriptivo</p>
</div>
</div>
<div class="gn-table__container">
<table class="gn-table__element" aria-labelledby="table-sortable-title">
<caption class="sr-only">Tabla ordenable con efecto hover en filas</caption>
<thead>
<tr>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
<th class="gn-table__th gn-table__th--sorted-desc" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado (orden descendente)">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
</tbody>
</table>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initTableChecks();
});
5. Tabla ordenable con hover — variante compacta
Tabla ordenable con hover
Hint descriptivo
| Dato | Dato | Dato |
| Dato | Dato | Dato |
| Dato | Dato | Dato |
| Dato | Dato | Dato |
| Dato | Dato | Dato |
Mostrar HTML
<div class="gn-table gn-table--compact" data-gn-table-hover data-gn-table-sort-demo>
<div class="gn-table__label">
<div class="gn-table__label-copy">
<h4 class="gn-table__title" id="table-sortable-compact-title">Tabla ordenable con hover</h4>
<p class="gn-field__hint gn-table__hint">Hint descriptivo</p>
</div>
</div>
<div class="gn-table__container">
<table class="gn-table__element" aria-labelledby="table-sortable-compact-title">
<caption class="sr-only">Tabla ordenable compacta con efecto hover</caption>
<thead>
<tr>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
<th class="gn-table__th gn-table__th--sorted-desc" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado (orden descendente)">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
<th class="gn-table__th" scope="col">
<button type="button" class="gn-table__th-head" aria-label="Ordenar por encabezado">
<span class="gn-table__th-text">Encabezado</span>
</button>
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
<tr>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
<td class="gn-table__td">Dato</td>
</tr>
</tbody>
</table>
</div>
</div>
Mostrar JS
document.addEventListener('DOMContentLoaded', () => {
window.GNDS.initTableChecks();
});
gn-table es un pattern compuesto con 3 capas diferenciadas:
- Label de tabla: título, hint y acciones.
- Cabecera de filtros: bloque opcional alineable a izquierda, centro o derecha.
- Tabla de datos: celdas con
border-bottomy variante de filas en fondo gris.
Estructura recomendada
- Contenedor raíz:
.gn-table - Label:
.gn-table__label+.gn-table__label-copy+.gn-table__label-actions - Header de filtros:
.gn-table__headercon modificador:
- .gn-table__header--left - .gn-table__header--center - .gn-table__header--right
- Tabla:
- .gn-table__container - .gn-table-wrapper (opcional para scroll horizontal en tablas anchas) - .gn-table__element - caption (obligatorio, visible o sr-only) - .gn-table__th - .gn-table__td - .gn-table__row--muted para filas en gris
- Footer opcional de tabla:
.gn-table__footer(por ejemplo con paginación) - Navegación por filas opcional:
- data-gn-table-hover en .gn-table - data-gn-table-hover-toggle en el control que activa el resaltado
Modularidad (bloques opcionales)
El pattern está preparado para usar solo las piezas necesarias. Combinaciones válidas:
- Solo tabla (
.gn-table__container+.gn-table__element) - Label sin acciones
- Label con hint y sin botones
- Label con un único botón o varios
- Cabecera con filtros o sin filtros
- Tabla con checkboxes o sin checkboxes
- Tabla con resaltado de fila por hover activable o sin él
- Tabla con paginación (
.gn-table__footer) o sin paginación
Los wrappers vacíos se colapsan automáticamente (:empty) en:
.gn-table__label-actions.gn-table__hint.gn-table__header.gn-table__footer
Filtros en cabecera
La cabecera de filtros puede integrar:
gn-select gn-select--smgn-searchbar gn-searchbar--sm gn-searchbar--input-only
Variante de filas en fondo gris
- El fondo gris usa
--gn-color-fill-neutral-light. - Puede usarse como estilo fijo (
.gn-table__row--muted). - También puede activarse en navegación por filas con JS (
data-gn-table-hover-enabled="true"), de forma que al pasar por cada fila se resalte con ese mismo color.
Accesibilidad
- Usar
table,thead,tbody,thytdsemánticos. - Incluir siempre
captionpara describir el contenido de la tabla. - Definir
scope="col"en cabeceras. - Usar
scope="row"cuando la primera celda de la fila actúe como encabezado de fila. - Las tablas informativas y las tablas con interacción simple no usan
role="grid"nitabindexentable,trotd. role="grid"solo aplica en patrones tipo hoja de cálculo con navegación por flechas y roving tabindex.- Mantener etiquetas accesibles en filtros (
labelvisible osr-only). - Añadir
aria-labelen la tabla o enlazar con un título cuando aplique.
Relación con paginación
Cuando se requiera paginado, se recomienda componer gn-pagination justo debajo de la tabla, dentro de .gn-table__footer.