Version: 4.xx.xx
Source CodeTanStack Table
Refine provides an integration package for TanStack Table library. This package enables you to manage your tables in a headless manner. This adapter supports all of the features of both TanStack Table and Refine's useTable hook (sorting, filtering pagination etc). Simply, you can use any of the TanStack Table examples as-is by copying and pasting them into your project.
Installation
Install the @refinedev/react-table library.
- npm
- pnpm
- yarn
npm i @refinedev/react-table
pnpm add @refinedev/react-table
yarn add @refinedev/react-table
Usage
Let's see how to display a table with useTable hook.
We provide implementation examples for the Mantine and Chakra UI. If you using a different ui library, you can use the headless example as a starting point.
- Headless
- MantineTanStack Table
- Chakra UITanStack Table
import React from "react";import { useTable } from "@refinedev/react-table";import { ColumnDef, flexRender } from "@tanstack/react-table";export const ProductTable: React.FC = () => {const columns = React.useMemo<ColumnDef<IProduct>[]>(() => [{id: "id",header: "ID",accessorKey: "id",meta: {filterOperator: "eq",},},{id: "name",header: "Name",accessorKey: "name",meta: {filterOperator: "contains",},},{id: "price",header: "Price",accessorKey: "price",meta: {filterOperator: "eq",},},],[],);const {getHeaderGroups,getRowModel,getState,setPageIndex,getCanPreviousPage,getPageCount,getCanNextPage,nextPage,previousPage,setPageSize,} = useTable<IProduct>({refineCoreProps: {resource: "products",},columns,});return (<div><h1>Products</h1><table><thead>{getHeaderGroups().map((headerGroup) => (<tr key={headerGroup.id}>{headerGroup.headers.map((header) => {return (<th key={header.id}>{header.isPlaceholder ? null : (<><divonClick={header.column.getToggleSortingHandler()}>{flexRender(header.column.columnDef.header,header.getContext(),)}{{asc: " 🔼",desc: " 🔽",}[header.column.getIsSorted() as string] ?? " ↕️"}</div></>)}{header.column.getCanFilter() ? (<div><inputvalue={(header.column.getFilterValue() as string) ??""}onChange={(e) =>header.column.setFilterValue(e.target.value,)}/></div>) : null}</th>);})}</tr>))}</thead><tbody>{getRowModel().rows.map((row) => {return (<tr key={row.id}>{row.getVisibleCells().map((cell) => {return (<td key={cell.id}>{flexRender(cell.column.columnDef.cell,cell.getContext(),)}</td>);})}</tr>);})}</tbody></table><div><buttononClick={() => setPageIndex(0)}disabled={!getCanPreviousPage()}>{"<<"}</button><buttononClick={() => previousPage()}disabled={!getCanPreviousPage()}>{"<"}</button><button onClick={() => nextPage()} disabled={!getCanNextPage()}>{">"}</button><buttononClick={() => setPageIndex(getPageCount() - 1)}disabled={!getCanNextPage()}>{">>"}</button><span>Page<strong>{getState().pagination.pageIndex + 1} of{" "}{getPageCount()}</strong></span><span>| Go to page:<inputtype="number"defaultValue={getState().pagination.pageIndex + 1}onChange={(e) => {const page = e.target.value? Number(e.target.value) - 1: 0;setPageIndex(page);}}/></span>{" "}<selectvalue={getState().pagination.pageSize}onChange={(e) => {setPageSize(Number(e.target.value));}}>{[10, 20, 30, 40, 50].map((pageSize) => (<option key={pageSize} value={pageSize}>Show {pageSize}</option>))}</select></div></div>);};interface IProduct {id: number;name: string;price: string;}
import React from "react";import { useTable } from "@refinedev/react-table";import { ColumnDef, flexRender } from "@tanstack/react-table";import { Box, Group, Table, Pagination } from "@mantine/core";import { ColumnSorter } from "./column-sorter.tsx";import { ColumnFilter } from "./column-filter.tsx";export const ProductTable: React.FC = () => {const columns = React.useMemo<ColumnDef<IProduct>[]>(() => [{id: "id",header: "ID",accessorKey: "id",meta: {filterOperator: "eq",},},{id: "name",header: "Name",accessorKey: "name",meta: {filterOperator: "contains",},},{id: "price",header: "Price",accessorKey: "price",meta: {filterOperator: "eq",},},],[],);const {getHeaderGroups,getRowModel,refineCore: { setCurrent, pageCount, current },} = useTable({refineCoreProps: {resource: "products",},columns,});return (<div style={{ padding: "4px" }}><h2>Products</h2><Table highlightOnHover><thead>{getHeaderGroups().map((headerGroup) => (<tr key={headerGroup.id}>{headerGroup.headers.map((header) => {return (<th key={header.id}>{!header.isPlaceholder && (<Group spacing="xs" noWrap><Box>{flexRender(header.column.columnDef.header,header.getContext(),)}</Box><Group spacing="xs" noWrap><ColumnSortercolumn={header.column}/><ColumnFiltercolumn={header.column}/></Group></Group>)}</th>);})}</tr>))}</thead><tbody>{getRowModel().rows.map((row) => {return (<tr key={row.id}>{row.getVisibleCells().map((cell) => {return (<td key={cell.id}>{flexRender(cell.column.columnDef.cell,cell.getContext(),)}</td>);})}</tr>);})}</tbody></Table><br /><Paginationposition="right"total={pageCount}page={current}onChange={setCurrent}/></div>);};interface IProduct {id: number;name: string;price: string;}
import React from "react";import { useTable } from "@refinedev/react-table";import { ColumnDef, flexRender } from "@tanstack/react-table";import {Table,Thead,Tbody,Tr,Th,Td,TableContainer,HStack,Text,} from "@chakra-ui/react";import { Pagination } from "./pagination";import { ColumnSorter } from "./column-sorter";import { ColumnFilter } from "./column-filter";export const ProductTable: React.FC = () => {const columns = React.useMemo<ColumnDef<IProduct>[]>(() => [{id: "id",header: "ID",accessorKey: "id",meta: {filterOperator: "eq",},},{id: "name",header: "Name",accessorKey: "name",meta: {filterOperator: "contains",},},{id: "price",header: "Price",accessorKey: "price",meta: {filterOperator: "eq",},},],[],);const {getHeaderGroups,getRowModel,refineCore: { setCurrent, pageCount, current },} = useTable({refineCoreProps: {resource: "products",},columns,});return (<div style={{ padding:"8px" }}><Text fontSize='3xl'>Products</Text><TableContainer whiteSpace="pre-line"><Table variant="simple"><Thead>{getHeaderGroups().map((headerGroup) => (<Tr key={headerGroup.id}>{headerGroup.headers.map((header) => (<Th key={header.id}>{!header.isPlaceholder && (<HStack spacing="2"><Text>{flexRender(header.column.columnDef.header,header.getContext(),)}</Text><HStack spacing="2"><ColumnSortercolumn={header.column}/><ColumnFiltercolumn={header.column}/></HStack></HStack>)}</Th>))}</Tr>))}</Thead><Tbody>{getRowModel().rows.map((row) => (<Tr key={row.id}>{row.getVisibleCells().map((cell) => (<Td key={cell.id}>{flexRender(cell.column.columnDef.cell,cell.getContext(),)}</Td>))}</Tr>))}</Tbody></Table></TableContainer><Paginationcurrent={current}pageCount={pageCount}setCurrent={setCurrent}/></div>);};interface IProduct {id: number;name: string;price: string;}