Saltar al contenido
EspañolEnglish
Todos los componentes (204)

Tabla

Datos · Table · .amset-table

Qué es y cuándo usarlo

Datos que se comparan por columnas (facturas, pedidos, clientes), con orden, filtros por columna, selección, paginación, columnas configurables y totales al pie.

Cuándo usarlo

  • Listados de gestión en los que se busca, se ordena y se actúa sobre filas.
  • Ordena, filtra, selecciona y pagina sola. Los callbacks (onSort, onFilter, onSelectionChange, onVisibleColumnsChange, pagination.onPageChange) solo avisan: cada parte la controla quien la usa solo si le pasa también su valor (sort, filters, selectedKeys, visibleColumns, pagination.page). Estas fichas le pasan todos los callbacks y la tabla sigue funcionando sola.
  • Con serverSide (o con pagination.total) no ordena ni filtra en local: pinta las filas tal como llegan, y quien la usa pide al servidor lo que dicen los avisos.
  • selection="multiple" con selectionActions para acciones en masa; footer en una columna para sumar lo que queda tras filtrar.
  • renderExpandedRow convierte cada fila en desplegable, con su detalle a todo el ancho debajo; maxHeight fija el alto y deja quietas la cabecera y el pie.
  • Sin paginación y dentro de un contenedor con data-density="compact" en un cuadro de mando: la densidad es global, no una prop.

Cuándo no

  • Los datos de una sola cosa, etiqueta y valor: DataList.
  • Miles de filas que se recorren seguidas, sin columnas: VirtualList.
  • Una comparativa de planes o precios: PricingTable.
  • Una hoja de cálculo completa (fórmulas, selección de rangos, pegado masivo): la edición de aquí es celda a celda.

Más allá de lo básico

  • groupBy agrupa por una columna, con una cabecera plegable por grupo (initialCollapsedGroups, renderGroupLabel).
  • advancedFilters añade un panel de condiciones «columna · operador · valor» unidas por «y» o por «o» (texto, números, fechas y sí/no, con «entre» y «está vacío»); advancedFilter lo controla desde fuera.
  • exportCsv baja a CSV todas las filas filtradas y ordenadas en las columnas visibles (con BOM para Excel, el separador del idioma y los textos que parecen fórmula neutralizados). exportable: false deja fuera una columna.
  • persistKey recuerda columnas visibles, orden y anchos en el navegador; el panel de columnas ofrece «Restablecer».
  • editor en una columna + onCellEdit en la tabla: Intro, F2 o doble clic abren la celda; Intro guarda, Escape cancela, salir guarda. Si onCellEdit falla, el campo sigue abierto con el error. La tabla no cambia rows: quien la usa actualiza sus datos.
  • virtualized + maxHeight pinta solo las filas que se ven, para miles de filas (Inicio, Fin y las páginas saltan aunque la fila no esté pintada). No se combina con renderExpandedRow.

Teclado: la tabla es una sola parada de Tab. Arriba y abajo van de fila en fila, conservando la columna; la flecha derecha entra en las celdas (al control que tengan dentro, como la casilla de selección, que se marca con Espacio) y la izquierda vuelve a la fila. Inicio y Fin van a la primera y a la última fila. Pulsar la cabecera de una columna sortable ordena (con el foco en ella, también Intro o Espacio): ascendente, descendente y sin orden. El embudo de la cabecera abre el filtro (en el de texto, Intro filtra) y «Columnas» abre un panel con casillas y botones de subir y bajar, sin arrastrar nada.

Accesibilidad: es un <table> de verdad con papel de rejilla (role="grid"), nombre obligatorio (label), cabeceras con aria-sort y, con rowHeader, la columna que nombra cada fila. Con el filtro puesto, el botón cambia de nombre («Filtro de Cliente (activo)») y de forma, no solo de color: el embudo se rellena, igual que el orden activo apaga una de sus dos flechas. Los dos son cajas iguales de 22 px junto al título. La barra de selección («3 filas seleccionadas») y el recuento de páginas van en role="status". Mientras carga (loading) lleva aria-busy y, si aún no hay filas, dice «Cargando…».

Aspecto fino: variables CSS --amset-table-*: -cell, -column, -font, -padding-row, -radius, -row. El tamaño mueve el relleno de la celda y el cuerpo de letra. El de arriba y abajo lo manda la densidad (data-density) cuando la hay.

Cómo se ve

PedidoClienteEstadoTotal
1041Aitor EtxeberriaEnviado1249,00 €
1039Javier OrtegaEnviado420,00 €
1043Pablo GilEntregado315,50 €
1038Lucía MartínEntregado189,00 €
1042Nerea SánchezPendiente89,00 €

<Table
  label="Pedidos de octubre"
  columns={[
    { key: 'id', title: 'Pedido', rowHeader: true },
    { key: 'cliente', title: 'Cliente', sortable: true, filterable: 'text' },
    { key: 'estado', title: 'Estado', filterable: 'list' },
    { key: 'total', title: 'Total', numeric: true, sortable: true },
  ]}
  rows={pedidos}
  rowKey={(pedido) => pedido.id}
  initialSort={{ column: 'total', direction: 'desc' }}
  pagination={{ size: 5, sizes: [5, 10] }}
/>

Props

Se importa con import { Table } from '@amset/ui'. Las obligatorias van marcadas.

PropTipoPara qué sirve
columnsobligatoriareadonly TableColumn<T>[]—
labelobligatoriastringLo que se anuncia al entrar en la tabla. Obligatorio: sin esto es "tabla" a secas.
rowKeyobligatoria(row: T) => string—
rowsobligatoriareadonly T[]—
advancedFilterAdvancedFilterEl filtro avanzado, controlado desde fuera. Sin el, lo lleva la tabla.
advancedFiltersbooleanAñade el panel de filtros con varias condiciones unidas por «y» / «o».
classNamestringSe une a las clases de la biblioteca, no las sustituye.
configurableColumnsbooleanAñade el panel para mostrar, ocultar y reordenar columnas.
emptyMessagestring—
expandedKeysreadonly string[]Filas desplegadas (por su clave), controladas desde fuera. Sin ellas, las lleva la tabla.
exportCsvboolean | TableExportOptionsAñade un boton que baja a CSV lo que se ve en las columnas visibles: todas las filas ya filtradas y ordenadas, no solo la pagina. Con `serverSide` solo exporta las filas cargadas.
filtersReadonly<Record<string, string | readonly string[]>>Filtros controlados desde fuera. Sin ellos, los lleva la tabla.
groupBystringAgrupa las filas por el valor de esta columna, con una fila de cabecera por grupo que se pliega.
initialCollapsedGroupsreadonly string[]Grupos plegados al empezar (por el valor de su clave).
initialExpandedKeysreadonly string[]Las filas desplegadas al empezar, sin controlarlas desde fuera.
initialSortTableSort | null—
loadingboolean—
maxHeightstringAlto maximo de la tabla (`'24rem'`, `'60vh'`): pasado, el cuerpo se desplaza y la cabecera y el pie se quedan fijos. Es la variable `--amset-table-height` hecha prop.
onAdvancedFilterChange(filter: AdvancedFilter) => voidAvisa del filtro avanzado nuevo. Solo avisa: no controla nada.
onCellEdit(edit: CellEdit<T>) => void | Promise<void>Guarda lo editado en una celda con `editor`. Se abre con Intro, F2 o doble clic y se cierra con Intro (guarda), Escape (cancela) o saliendo del campo (guarda). Puede ser asincrona: si lanza, el campo sigue abierto con el error. La tabla NO cambia `rows`: quien la usa actualiza sus datos.
onExpandedChange(keys: readonly string[]) => voidAvisa con las claves desplegadas. Solo avisa: no controla ni apaga nada.
onFilter(filters: TableFilters) => voidAvisa de los filtros nuevos. Solo avisa: no controla ni apaga nada.
onRowPress(row: T) => voidAvisa de la fila pulsada. Desplegar el detalle no cuenta.
onSelectionChange(keys: readonly string[]) => voidAvisa con las claves seleccionadas. Solo avisa: no controla nada.
onSort(sort: TableSort | null) => voidAvisa del orden nuevo, o `null` al quitarlo. Solo avisa: no controla ni apaga nada.
onVisibleColumnsChange(keys: readonly string[]) => voidAvisa con las columnas visibles, en su orden. Solo avisa: no controla nada.
paginationfalse | TablePagination—
persistKeystringRecuerda entre visitas que columnas se ven, en que orden y con que ancho, en el navegador, bajo esta clave. Con `visibleColumns` controlado no recuerda las visibles.
renderExpandedRow(row: T) => ReactNodeConvierte cada fila en desplegable y pinta aqui su detalle: un pedido con sus lineas, un cliente con su historial. Cada fila gana un boton con `aria-expanded` al principio y el detalle sale en una fila debajo, de ancho completo. Quien no tiene nada que desplegar se marca con `rowExpandable`.
renderGroupLabel(value: CellValue, rows: readonly T[]) => ReactNodeLo que dice la cabecera de un grupo. Por defecto, el valor y el recuento.
resizableColumnsbooleanSe puede arrastrar el borde de cada cabecera para cambiar el ancho de la columna.
rowClassName(row: T, index: number) => string | undefinedUna clase para marcar una fila concreta -una factura vencida en rojo- sin tocar el CSS global. Se SUMA a las de la tabla. `index` es la posicion en la pagina que se ve.
rowExpandable(row: T) => booleanQue filas se pueden desplegar. Por defecto, todas.
selectedKeysreadonly string[]Claves seleccionadas, controladas desde fuera. Sin ellas, las lleva la tabla.
selectionSelectionMode—
selectionActions(keys: readonly string[]) => ReactNodeBarra que aparece cuando hay filas seleccionadas.
serverSidebooleanOrdenar y filtrar lo hace el servidor: la tabla pinta `rows` tal como llegan y solo avisa con `onSort` y `onFilter`. Con `pagination.total` es asi sin pedirlo, porque ordenar en local una sola pagina no tiene sentido.
size"sm" | "md" | "lg"El tamaño de la tabla: mueve el relleno de las celdas y el cuerpo de letra. No confundir con `pagination.size`, que son las filas por pagina.
sortTableSort | nullOrden controlado desde fuera. Sin el, lo lleva la tabla empezando en `initialSort`.
toolbarReactNodeContenido propio en la barra de arriba (buscador, botón de exportar...).
virtualizedboolean | TableVirtualizationPinta solo las filas que se ven, para miles de filas. Necesita `maxHeight` (sin alto no hay desplazamiento) y no se combina con `renderExpandedRow`, cuyas filas miden distinto.
visibleColumnsreadonly string[]Columnas visibles y su orden, controladas desde fuera. Sin ellas, las lleva la tabla.

Acepta además los atributos del elemento que pinta: className, style, data-*, aria-* y sus eventos.

Mandos

Estas variables CSS son la forma de adaptarlo. Se declaran sobre el selector del componente, no en :root: la hoja las redeclara en la propia regla y una declaración en el mismo elemento gana siempre.

VariablePor defecto
--amset-table-rowvar(--amset-space-2)
--amset-table-cellvar(--amset-space-3)
--amset-table-fontvar(--amset-text-base)
--amset-table-columnvar(--amset-text-sm)
--amset-table-radiusvar(--amset-radius-lg)

Cómo se cambia

.amset-table {
  --amset-table-row: ...;
  --amset-table-cell: ...;
}

En el banco de pruebas

Cada estado y cada variante, para tocarlos de uno en uno, en su ficha de ui.amset.tech: