Data table
Una tabla para datos reales, con ordenación, búsqueda, selección de filas, columnas fijadas, un encabezado fijo y paginación.
| Method | Country | |||||
|---|---|---|---|---|---|---|
| [email protected] | Card | United States | 2026-01-01 | $5.00 | ||
| [email protected] | PayPal | Japan | 2026-02-02 | $84.20 | ||
| [email protected] | Bank | Germany | 2026-03-03 | $163.40 | ||
| [email protected] | Apple Pay | Brazil | 2026-04-04 | $242.60 | ||
| [email protected] | Card | India | 2026-05-05 | $321.80 | ||
| [email protected] | PayPal | United States | 2026-06-06 | $401.00 | ||
| [email protected] | Bank | Japan | 2026-07-07 | $480.10 | ||
| [email protected] | Apple Pay | Germany | 2026-08-08 | $559.30 | ||
| [email protected] | Card | Brazil | 2026-09-09 | $638.50 | ||
| [email protected] | PayPal | India | 2026-01-10 | $717.70 |
pnpm dlx shadcn@latest add https://hextaui.com/r/data-table.jsonAñade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.
Añade los tokens del tema a tu CSS global, si aún no lo has hecho.
Instala las dependencias.
pnpm add @base-ui/react @tabler/icons-react @tanstack/react-table class-variance-authority cnCopia y pega el siguiente código en tu proyecto.
components/ui/data-table.tsx components/ui/table.tsx components/ui/button.tsx components/ui/checkbox.tsx components/ui/skeleton.tsx Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
La data table es TanStack Table v9 con las funciones de ordenación, filtrado, paginación, selección y visibilidad de columnas ya conectadas. Define las columnas una vez con createDataTableColumns, crea la tabla con useDataTable y luego compón las partes que necesites.
Pasa cualquier estado de TanStack que quieras controlar, como sorting o la selección de filas, con su manejador de cambio.
DataTableColumnHeader, DataTableSelectAll y DataTableSelectRow van en las definiciones de tus columnas, como encabezado o celda de una columna.
Tabla simple
Las partes simples de <Table /> con las que se construye la data table. Úsalas por separado para datos estáticos, con un caption y un total en el pie.
Cargando
Con loading, las filas skeleton ocupan el mismo espacio que las filas reales, así que nada salta cuando llegan los datos. Mientras tanto, la tabla se marca con aria-busy.
Empty
emptyMessage llena el cuerpo cuando no hay datos o nada coincide con la búsqueda.
Encabezado fijo
Dale al contenedor una altura máxima con containerClassName y define stickyHeader. El encabezado permanece fijo y gana una línea fina cuando las filas se desplazan bajo él. Shift-arrastrar sobre los checkboxes desplaza la caja al acercarte a su borde.
Columnas ancladas
La columna de selección y la primera columna de datos están ancladas por defecto. Elige las tuyas con pinStart. Una sombra suave marca el borde cuando la tabla se desplaza hacia los lados.
De derecha a izquierda
Todas las etiquetas y contadores se pueden reemplazar con labels y las funciones de formato. Las flechas de paginación y las columnas ancladas se invierten con la dirección.
- Haz clic en un encabezado ordenable para ordenar de forma ascendente, de nuevo para descendente, y una tercera vez para quitar el orden. Shift-clic en otro encabezado para añadir un orden secundario.
- Shift-clic en el checkbox de una fila para seleccionar todas las filas entre ella y la última en que hiciste clic. Mantén Shift y arrastra sobre los checkboxes para seleccionar o borrar un rango de una sola vez.
- La búsqueda coincide con todas las columnas excepto la columna de selección y vuelve a la primera página.
- Ocultar columnas desde el menú View mantiene el menú abierto, así que puedes alternar varias a la vez.
| Key | Acción |
|---|---|
| Tab | Recorre la búsqueda, el menú View, los encabezados ordenables, los checkboxes de fila y la paginación. |
| EnterSpace | Ordena por el encabezado con foco. |
| Space | Alterna el checkbox con foco. |
| Esc | Borra la búsqueda cuando tiene texto. |
- Los encabezados ordenables llevan
aria-sort, y una región activa polite anuncia el nuevo orden y, poco después de escribir, el número de resultados. - El indicador de página es una región activa, así que los lectores de pantalla oyen la nueva página tras pulsar siguiente o anterior.
- Los checkboxes tienen etiquetas por defecto. Reemplázalas con
aria-labelen<DataTableSelectAll />y<DataTableSelectRow />.
Cada parte de abajo debe renderizarse dentro de <DataTable />, que comparte la tabla con ellas.
Acepta las opciones de TanStack Table y devuelve la tabla. Las páginas contienen 10 filas salvo que initialState.pagination indique otra cosa.
| Prop | Tipo | Predeterminado |
|---|---|---|
data | TData[] | – |
columnsConstrúyelas con createDataTableColumns. | ColumnDef[] | – |
getRowIdMantiene estable la selección cuando las filas se mueven. Por defecto es el índice de la fila. | (row: TData) => string | – |
initialState | Partial<TableState> | { pagination: { pageIndex: 0, pageSize: 10 } } |
stateControla sorting, rowSelection, globalFilter, pagination o columnVisibility. | Partial<TableState> | – |
onSortingChangeCada estado controlable tiene un manejador correspondiente, como onRowSelectionChange. | OnChangeFn<SortingState> | – |
enableRowSelection | boolean | (row) => boolean | true |
Devuelve un column helper tipado con accessor, display y columns. Define meta: { align: "end" } en las columnas numéricas para alinear el encabezado y las celdas.
| Prop | Tipo | Predeterminado |
|---|---|---|
tableLa tabla devuelta por useDataTable. | DataTableInstance<TData> | – |
className | string | – |
| Atributo | Descripción |
|---|---|
data-slot="data-table" | El contenedor alrededor de todas las partes. |
data-slot="data-table-announcer" | La región activa oculta visualmente. |
| Prop | Tipo | Predeterminado |
|---|---|---|
emptyMessage | ReactNode | "No results." |
loading | boolean | false |
loadingRowsNúmero de filas skeleton durante la carga. | number | 5 |
pinStartIds de columna que se anclan al borde inicial. | string[] | ["select", firstColumnId] |
stickyHeaderNecesita una altura máxima en el contenedor. | boolean | false |
containerClassNameSe aplica al contenedor de desplazamiento. | string | – |
swipeSelectShift-arrastra sobre los checkboxes para seleccionar un rango. | boolean | true |
classNameSe aplica al elemento table. | string | – |
| Atributo | Descripción |
|---|---|
data-slot="table-container" | El contenedor de desplazamiento. |
data-scrolled-start | Presente en el contenedor cuando se ha desplazado lejos del borde inicial. |
data-scrolled-end | Presente mientras queda más por desplazar hacia el borde final. |
data-scrolled-top | Presente una vez que las filas se desplazan verticalmente. |
data-swipe-selecting | Presente en el contenedor durante un Shift-arrastre. |
data-state="selected" | Presente en las filas seleccionadas. |
data-row-id | El id de fila de getRowId. |
data-slot="data-table-loading-row" | Cada fila skeleton. |
data-slot="data-table-empty" | La fila vacía. |
Una fila que se ajusta para la búsqueda, el menú View y tus propios filtros. Acepta todas las props de div y lleva data-table-toolbar como su data-slot.
| Prop | Tipo | Predeterminado |
|---|---|---|
placeholder | string | "Search…" |
aria-label | string | "Search table" |
clearLabelNombre accesible del botón de borrar. | string | "Clear search" |
| Atributo | Descripción |
|---|---|
data-slot="data-table-search" | El contenedor del campo de búsqueda. |
| Prop | Tipo | Predeterminado |
|---|---|---|
label | string | "View" |
groupLabel | string | "Toggle columns" |
getLabelPor defecto es el encabezado de tipo cadena de la columna, o su id en mayúscula inicial. | (column) => string | – |
Lista todas las columnas que se pueden ocultar. Define enableHiding: false en una columna para dejarla fuera.
| Atributo | Descripción |
|---|---|
data-slot="data-table-view-options" | El popup del menú. |
| Prop | Tipo | Predeterminado |
|---|---|---|
column | Column | – |
title | string | – |
Renderiza un botón de orden para las columnas ordenables y texto simple para el resto.
| Atributo | Descripción |
|---|---|
data-slot="data-table-column-header" | El contenedor del encabezado. |
data-sorted | Presente en el botón de orden mientras la columna está ordenada. |
aria-sort | En la celda de encabezado: ascendente, descendente o ninguno. |
| Prop | Tipo | Predeterminado |
|---|---|---|
table | Table | – |
aria-label | string | "Select all rows on this page" |
Selecciona las filas de la página actual y muestra un estado indeterminado cuando solo algunas están seleccionadas.
| Prop | Tipo | Predeterminado |
|---|---|---|
row | Row | – |
aria-label | string | "Select row" |
| Prop | Tipo | Predeterminado |
|---|---|---|
pageSizes | number[] | [10, 20, 50, 100] |
showSelectionMuestra el número de seleccionados en lugar del número de filas. | boolean | true |
labelsrowsPerPage, firstPage, previousPage, nextPage y lastPage. | Partial<DataTablePaginationLabels> | – |
formatSelection | (selected: number, total: number) => ReactNode | "2 of 42 rows selected" |
formatRows | (total: number) => ReactNode | "42 rows" |
formatPage | (page: number, pageCount: number) => ReactNode | "Page 1 of 5" |
| Atributo | Descripción |
|---|---|
data-slot="data-table-pagination" | La barra de paginación. |
Devuelve la tabla del <DataTable /> más cercano. Úsalo para construir tus propios controles de barra de herramientas, como un filtro de estado.
| Prop | Tipo | Predeterminado |
|---|---|---|
stickyHeaderAncla la fila de encabezado dentro de un contenedor con desplazamiento. | boolean | false |
containerClassNameSe aplica al contenedor de desplazamiento. | string | – |
containerRef | Ref<HTMLDivElement> | – |
| Atributo | Descripción |
|---|---|
data-slot="table" | El elemento table. |
data-sticky-header | Presente en el contenedor cuando stickyHeader está activado. |
--table-bg | Fondo de la fila y de las celdas ancladas. Sigue a la tarjeta o al popover en que se encuentra. |
| Prop | Tipo | Predeterminado |
|---|---|---|
alignLas celdas alineadas al final también usan números tabulares. | "start" | "center" | "end" | "start" |
pinnedMantiene la celda en su sitio mientras la tabla se desplaza hacia los lados. Se desplaza con --pin-offset. | "start" | "end" | – |
pinnedEdgeDibuja una sombra suave en la última columna anclada mientras se desplaza. | boolean | false |
| Atributo | Descripción |
|---|---|
data-align | La alineación actual. |
data-pinned | start o end cuando está anclado. |
data-pinned-edge | Presente en la última celda anclada de un lado. |
--pin-offset | Distancia desde el borde anclado, definida por ti. |
TableHeader, TableBody, TableFooter, TableRow y TableCaption renderizan los elementos de tabla correspondientes y aceptan todas sus props.
- ButtonBotones en todas las variantes y tamaños, con un flujo integrado de carga, éxito y error que omite el spinner en las peticiones rápidas.
- CheckboxUna casilla de verificación cuya marca se dibuja, con padres indeterminados, grupos y etiquetas que comparten su hover.
- SkeletonMarcadores de posición que esperan 150ms antes de mostrarse, toman el tamaño exacto del contenido que envuelven y lo hacen aparecer con un fundido sin mover nada.
- TableUna tabla responsive con estilo de superficie, celdas que se ajustan o compactas, encabezados fijos, columnas ancladas e indicadores de desplazamiento.
- AvatarFotos de usuario con iniciales como alternativa, insignias de estado y grupos apilados que se colapsan en un contador.
- BadgeEtiquetas de estado con puntos de color, tags eliminables que se deslizan al cerrarse y contadores que ruedan hasta su nuevo valor.