DataTablePRO

Tabla avanzada todo-en-uno con búsqueda global, sort multi-columna, filtros por columna (texto, select, avanzado), paginación interna, selección de filas con acciones masivas, visibilidad de columnas, exportación CSV/JSON y modo de carga skeleton. Cero dependencias externas.

Contactos CRM

Clientes y prospectos activos
AL
Ana López
Kuro Games SL
EspañaActivo€ 280012 mar 2024
BD
Bruno Díaz
HoYoverse Europe
AlemaniaActivo€ 52005 nov 2023
CR
Carla Ruiz
Level-5 Studios
EspañaProspecto20 ene 2026
DM
Diego Mora
Cygames Inc.
JapónActivo€ 910018 jul 2022
EV
Elena Vidal
Square Enix
FranciaInactivo29 abr 2023

Instalación#

bash
pnpm add @tsukira/ui

Uso#

tsx
import { DataTable, defineColumns } from "@tsukira/ui"; interface Contacto { id: string; nombre: string; mrr: number; } const columns = defineColumns<Contacto>([  { key: "nombre", header: "Nombre", sortable: true, searchable: true },  { key: "mrr",    header: "MRR",    sortable: true, align: "right",    dataType: "number", cell: (r) => `€ ${r.mrr}` },]); <DataTable  data={contactos}  columns={columns}  rowKey={(r) => r.id}  searchable  pageSize={10}/>

Ejemplos#

Sorting y paginación interna

Haz clic en las cabeceras para ordenar · pageSize controla filas por página
MRR
Diego MoraCygames Inc.€ 9100
Karen BlancoFrom Software€ 7800
Bruno DíazHoYoverse Europe€ 5200

Selección y acciones masivas

selectable activa checkboxes · bulkActions aparece al seleccionar filas
Estado
MRR
Ana LópezActivo€ 2800
Bruno DíazActivo€ 5200
Carla RuizProspecto
Diego MoraActivo€ 9100

Densidad y cabecera fija

density='compact' · stickyHeader · maxBodyHeight habilita scroll vertical interno
MRR
Ana LópezKuro Games SLEspaña€ 2800
Bruno DíazHoYoverse EuropeAlemania€ 5200
Carla RuizLevel-5 StudiosEspaña
Diego MoraCygames Inc.Japón€ 9100
Elena VidalSquare EnixFrancia
Fede GilBandai NamcoItalia€ 3400
Gema OrtizCapcom EuropeEspaña
Hugo SanzKonami DigitalMéxico
Irene PeñaAtlus WestArgentina€ 1650
Javier TorresGrasshopper Mfr.Colombia
Karen BlancoFrom SoftwarePortugal€ 7800
Luis MartínPlatinum GamesChile

Fusión: CRM con filtro de búsqueda externo

Input controlado que filtra el texto de búsqueda + DataTable con Chip de filtro activo removible
Estado
MRR
ALAna López
Kuro Games SLEspañaActivo€ 2800
BDBruno Díaz
HoYoverse EuropeAlemaniaActivo€ 5200
CRCarla Ruiz
Level-5 StudiosEspañaProspecto
DMDiego Mora
Cygames Inc.JapónActivo€ 9100

Fusión: acciones por fila

rowActions muestra un menú de opciones en cada fila — editar, ver perfil o eliminar
Estado
Actions
ALAna López
Kuro Games SLActivo
BDBruno Díaz
HoYoverse EuropeActivo
CRCarla Ruiz
Level-5 StudiosProspecto
DMDiego Mora
Cygames Inc.Activo

DataTable V2: Virtualización, Agrupamiento y Edición Inline

Doble click en Contacto, Estado o MRR para editar · Agrupa por País/Estado · Soporta 1000+ filas de forma fluida
|
Agrupar por:

Virtualización y Edición Inline (V2)

Doble click en Contacto, Estado o MRR para modificar en tiempo real
AL
Ana López
Kuro Games
EspañaActivo
IL
Irene López
Atlus
EspañaActivo€ 1200
EL
Elena López
Capcom
EspañaActivo€ 2400
AL
Ana López
Square Enix
EspañaActivo€ 3600
IL
Irene López
Level-5
EspañaActivo€ 4800
EL
Elena López
Kuro Games
EspañaActivo€ 6000
AL
Ana López
Atlus
EspañaActivo€ 7200
IL
Irene López
Capcom
EspañaActivo€ 8400
EL
Elena López
Square Enix
EspañaActivo€ 9600
AL
Ana López
Level-5
EspañaActivo€ 10.800
IL
Irene López
Kuro Games
EspañaActivo€ 12.000
EL
Elena López
Atlus
EspañaActivo€ 13.200
AL
Ana López
Capcom
EspañaActivo€ 14.400
IL
Irene López
Square Enix
EspañaActivo€ 600
EL
Elena López
Level-5
EspañaActivo€ 1800

API#

DataTablePropsextends Omit<HTMLAttributes<HTMLDivElement>, 'onSelect' | 'title' | 'style'>
PropTipoDefaultDescripción
styleReact.CSSPropertiesEstilo inline del root.
data*T[]Filas.
columns*Column<T>[]Definición de columnas.
rowKey*(row: T, index: number) => string | numberIdentificador único por fila. `index` es el índice **global** dentro de `data`.
titleAs'h2' | 'h3' | 'h4' | 'h5' | 'div'`'h3'`Heading tag para el título — default `'h3'`. Usa `'div'` para no afectar el outline a11y.
descriptionReactNodeDescripción bajo el título.
toolbarActionsReactNodeAcciones libres en la toolbar (botones).
hideToolbarbooleanOcultar la toolbar completa.
searchKeysstring[]
searchPlaceholderstring
searchDebounceMsnumberDebounce de la búsqueda en ms.
initialSortSortState[]Sort inicial.
pageSizesnumber[][10,25,50,100])Tamaños seleccionables (default [10,25,50,100]).
hidePaginationboolean
selectedKeys(string | number)[]
onSelectionChange((keys: (string | number)[], rows: T[]) => void)
bulkActionsBulkAction[]Acciones masivas — se muestran cuando hay seleccionados.
expandedKeys(string | number)[]Claves expandidas (controlled).
defaultExpandedKeys(string | number)[]Claves expandidas inicialmente (uncontrolled).
onExpandedChange((keys: (string | number)[]) => void)
showColumnsMenubooleanMostrar el menú de columnas en la toolbar.
showDensityToggleboolean
stripedboolean
stickyHeaderbooleanHeader pegajoso al hacer scroll vertical.
maxBodyHeightnumber | stringAltura máxima del body — habilita scroll vertical interno.
emptyReactNode
loadingboolean
skeletonRowsnumbermin(pageSize, 8) o 5Nº de filas skeleton a renderizar cuando `loading`. Default: min(pageSize, 8) o 5.
errorReactNodeSi se pasa, muestra el estado de error en vez del body.
onRetry(() => void)Si se pasa junto con `error`, renderiza un botón "Reintentar".
exportablebooleanHabilita botón export (CSV).
exportFilenamestringNombre del archivo exportado (sin extensión).
onExport((rows: T[], context: { format: 'csv' | 'json'Custom export handler (si se pasa, sobrescribe el export default).
scope*'all' | 'selected' | 'page' }) => void)
exportOptions{ formats?: ('csv' | 'json')[]Si se pasa, el botón "Exportar" abre un menú con formato + alcance. Sin esta prop, el click exporta directamente todos los filtrados como CSV.
scopes('all' | 'selected' | 'page')[]
onRefresh(() => void | Promise<unknown>)Mostrar botón refresh (llama onRefresh). Si devuelve `Promise`, el icono gira hasta resolverse.
stalebooleanPinta un dot junto al icono refresh para señalar que los datos están desactualizados.
manualFilterbooleanSi true, no se filtra en cliente — sólo emite `onFilterChange`.
manualPaginationbooleanSi true, no se pagina en cliente — sólo emite `onPageChange`.
manualSearchbooleanSi true, no se busca en cliente — sólo emite `onSearchChange`.
totalRowsnumberTotal de filas (requerido para paginación server-side).
onSortChange((sorts: SortState[]) => void)
onFilterChange((filters: Record<string, FilterValue>) => void)
onPageChange((page: number, pageSize: number) => void)
onSearchChange((query: string) => void)
enableSavedViewsbooleanHabilita el menú de "Vistas guardadas" en la toolbar. Requiere `storageKey` para persistir (sin él, las vistas viven sólo en memoria de la sesión).
rowHeightnumberAltura de fila en px. Si se omite, se estima por la densidad de la tabla.
groupByKeystringKey de columna para agrupar filas.
onRowEditSave((row: T, rowIndex: number, key: string, newValue: any) => void | Promise<void>)Callback cuando se guarda una edición inline.