TanStack Table Implementation in React: Complete Guide
TanStack Table (formerly React Table) is a powerful headless table library that provides sorting, filtering, pagination, and many other features. In this guide, we'll build a complete data table component for an inventory management system.
TanStack Table (formerly React Table) is a powerful headless table library that provides sorting, filtering, pagination, and many other features. In this guide, we'll build a complete data table component for an inventory management system.
Installation
npm install @tanstack/react-tableBasic Table Setup
Let's create a reusable table component:
import {
useReactTable,
getCoreRowModel,
getFilteredRowModel,
getSortedRowModel,
getPaginationRowModel,
flexRender,
type ColumnDef,
} from "@tanstack/react-table";
function TanstackTable({ columns, data, isLoading, globalFilter }) {
const [rowSelection, setRowSelection] = useState({});
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
const [columnFilters, setColumnFilters] = useState([]);
const table = useReactTable({
data,
columns,
state: {
columnFilters,
globalFilter,
pagination,
rowSelection,
},
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onColumnFiltersChange: setColumnFilters,
onGlobalFilterChange: setGlobalFilter,
onPaginationChange: setPagination,
onRowSelectionChange: setRowSelection,
enableRowSelection: true,
enableGlobalFilter: true,
});
if (isLoading) return <div>Loading...</div>;
return (
<div className="space-y-4">
<table className="table" style={{ width: `${table.getTotalSize()}px` }}>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
{flexRender(header.column.columnDef.header, header.getContext())}
{header.column.getCanSort() && (
<span onClick={header.column.getToggleSortingHandler()}>
{header.column.getIsSorted() === "asc" ? " ▲" :
header.column.getIsSorted() === "desc" ? " ▼" : " ↕"}
</span>
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id} className={row.getIsSelected() ? "selected" : undefined}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
<div className="pagination-container">
<button onClick={() => table.firstPage()} disabled={!table.getCanPreviousPage()}>
{"<<"}
</button>
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
{"<"}
</button>
<span>
Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
</span>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
{">"}
</button>
<button onClick={() => table.lastPage()} disabled={!table.getCanNextPage()}>
{">>"}
</button>
</div>
</div>
);
}Defining Columns
Here's how to define columns for a products table:
import type { ColumnDef } from "@tanstack/react-table";
import type { Product } from "../../types";
const columns: ColumnDef<Product>[] = [
{
accessorKey: "name",
header: "Product Name",
cell: (row) => row.getValue(),
},
{
accessorKey: "sku",
header: "SKU",
cell: (row) => row.getValue(),
},
{
accessorKey: "categoryName",
header: "Category",
cell: (row) => row.getValue() || "N/A",
},
{
accessorKey: "price",
header: "Price",
cell: (row) => `$${(row.getValue() as number).toFixed(2)}`,
},
{
accessorKey: "stock",
header: "Stock",
cell: (row) => {
const stock = row.getValue() as number;
const minStock = row.row.original.minStock || 0;
return (
<span className={stock <= minStock ? "text-red-600 font-semibold" : ""}>
{stock}
</span>
);
},
},
];Using the Table Component
import TanstackTable from "../../components/TanstackTable/TanstackTable";
import { useGetProductsQuery } from "../../state/products/productSlice";
function Products() {
const [globalFilter, setGlobalFilter] = useState("");
const { data, isLoading, isError } = useGetProductsQuery({});
const products = data?.data || [];
return (
<div>
<input
value={globalFilter ?? ""}
onChange={(e) => setGlobalFilter(String(e.target.value))}
placeholder="Search products..."
className="px-4 py-2 border rounded-lg"
/>
<TanstackTable
columns={columns}
data={products}
isLoading={isLoading}
isError={isError}
globalFilter={globalFilter}
emptyMessage="No products found."
/>
</div>
);
}Row Selection
Adding row selection with checkboxes:
{
id: "select",
header: ({ table }) => (
<IndeterminateCheckbox
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
/>
),
cell: ({ row }) => (
<IndeterminateCheckbox
checked={row.getIsSelected()}
disabled={!row.getCanSelect()}
indeterminate={row.getIsSomeSelected()}
onChange={row.getToggleSelectedHandler()}
/>
),
size: 50,
},Conclusion
TanStack Table provides a flexible, performant solution for building complex data tables in React. With features like sorting, filtering, pagination, and row selection, it's perfect for inventory management systems and data-heavy applications. The headless design allows for complete customization while providing powerful features out of the box.