TanStack Table (React): Practical Tutorial, Setup, and Examples
A compact, practical guide to build interactive, headless React data tables with TanStack Table. Covers installation, core concepts, sorting, filtering, pagination, and performance patterns.
Overview: What TanStack Table is and why it matters
TanStack Table (the modern successor to react-table) is a headless utility for building fast, flexible, and accessible data tables in React. “Headless” means it focuses on logic and state management—columns, sorting, filtering, pagination, row selection—without imposing a UI, so you get full control of rendering and styling.
This architecture is great for production apps where performance and customization matter. You can compose behavior (sorting, grouping, virtualization) and render cells with React components, CSS frameworks, or design systems. For large datasets, TanStack Table works well with virtualization and server-driven queries.
The rest of this guide walks you through installation, a basic example, common interactive features (sorting, filtering, pagination), advanced patterns (controlled state, server-side), and performance/accessibility tips. If you prefer a compact walkthrough, consult a practical TanStack Table tutorial such as this TanStack Table tutorial for hands-on examples.
Installation & setup
TanStack Table is distributed as the @tanstack/react-table package. Install it with your package manager and pair it with React 18+. The core library is lightweight and only provides hooks—no UI—so you can integrate it into any component library or CSS system.
Common install commands are below. Choose your package manager:
npm i @tanstack/react-tableyarn add @tanstack/react-tablepnpm add @tanstack/react-table
After installation, import and use the useReactTable hook and define a columns array and row data. If you need server-side pagination or filtering, you’ll wire state to your data-fetching layer (for example React Query) and update the table’s state in a controlled manner.
Core concepts and architecture
Columns: TanStack Table columns are configuration objects that describe headers and cell rendering. You define accessor keys or cell renderers to map row data to UI. Columns can be nested for grouping, and you can attach meta data or custom functions for sorting and filtering.
Rows & state: Rows are plain objects (your data). The library manages derived rows, row models, and table state (sorting, pagination, filters) through the hook. You can use either internal state (uncontrolled) or feed the state from outside (controlled) to implement server-driven features.
Plugins & features: TanStack Table exposes modular capabilities like sorting, filtering, column visibility, pagination, and aggregation. Because it’s headless, plugin behavior is expressed via options and state rather than UI components—this yields maximum flexibility for customized interactions and high performance.
Basic example: minimal table
Below is a minimal, complete example that shows the required pieces: columns, data, and calling useReactTable. This renders a simple table with header and rows. The library returns table models and helper functions you consume in JSX.
// Example: Minimal TanStack Table (React)
import React from "react";
import { useReactTable, getCoreRowModel } from "@tanstack/react-table";
const columns = [
{ accessorKey: "id", header: "ID" },
{ accessorKey: "firstName", header: "First" },
{ accessorKey: "lastName", header: "Last" },
];
const data = [
{ id: 1, firstName: "Jane", lastName: "Doe" },
{ id: 2, firstName: "John", lastName: "Smith" },
];
export default function SimpleTable() {
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });
return (
<table>
<thead>
{table.getHeaderGroups().map(hg => (
<tr key={hg.id}>
{hg.headers.map(h => <th key={h.id}>{h.isPlaceholder ? null : h.renderHeader()}
That snippet uses core row modeling and the primary API. Notice renderHeader/renderCell helpers are used for consistent behavior. From here you can add sorting, filtering, and pagination by enabling the appropriate options and row models.
Sorting and filtering
Sorting and filtering are implemented by adding state and row models. For client-side sorting, include getSortedRowModel and manage state: { sorting } in the table options. For filtering, you define column filterFns and supply getFilteredRowModel. You can use built-in filter functions or write custom ones for complex needs.
Sorting example (conceptual): update the sorting state when a header is clicked and pass it into useReactTable. The table will recompute the sorted row model for rendering. For keyboard and accessibility, ensure header buttons are focusable and convey sort order.
Filtering: simple text filters can be implemented with an input that updates column filter state. For large datasets, consider server-side filtering: capture the filter state and send it as query params to your API, then update the data prop once the server responds. This keeps the client lightweight and scalable.
Pagination: client vs server
TanStack Table supports both client-side and server-side pagination. Client-side pagination slices the row model with getPaginationRowModel. You control pageIndex and pageSize in state for UI controls (next/prev/select page size).
Server-side pagination requires a controlled approach: track pageIndex and pageSize, send these to your backend, and replace the data prop with the response. Use a data-fetching library like React Query to handle caching, stale modes, and background refetching for a snappy UX.
Pagination UX tip: when fetching new pages, keep previous data visible and show a small loading indicator. Avoid full blank states on every fetch to reduce layout shift and improve perceived performance.
Controlled state, server integration, and real-world patterns
In production apps you often need to control table state externally—sorting, filters, pagination—so that each change triggers a network request. Pass the state into the table via options and respond to onStateChange callbacks by updating your fetch keys. This pattern enables server-side processing and deep-linkability of table state.
Integrating with React Query or SWR is straightforward: use your table state as part of the query key, and call refetch or let React Query manage background updates. Keep table state serializable (avoid functions in the state) for reproducible URLs and caching.
For editing and optimistic updates, keep the table's UI responsive by applying optimistic updates to row data and then reconciling with the server response. Always provide clear error handling and rollback strategies to maintain data integrity.
Advanced topics: virtualization, column virtualization, and plugins
Virtualization is essential for very large tables. Use libraries like react-virtual (from the TanStack family) to render only visible rows and drastically reduce DOM nodes. The headless nature of TanStack Table makes it trivial to combine with virtualization libraries because you control the DOM rendering loop.
Column virtualization is also possible but more complex—especially when you have sticky columns. Plan cell widths and use virtualization offsets carefully to avoid jitter. Test thoroughly across browsers and devices.
Other advanced topics include grouped headers, aggregated footers, and custom cell editors. Because the library is composable, you can build features incrementally and keep the core table logic consistent across your app.
Performance & accessibility
Performance: memoize column definitions and cell renderers to prevent unnecessary re-renders. Use stable references for functions passed into the table options. Prefer data transformations on the server where possible. For client-side operations, restrict heavy computations to web workers if needed.
Accessibility: TanStack Table gives you the logic but not the markup, so ensure you add proper table semantics (role, headers attributes, ARIA sort indicators). Use accessible keyboard interactions for header activation, row selection, and focus management. Test with screen readers to ensure a good experience.
Testing: unit-test the data transformation (sorting/filtering) and integration-test the rendering via testing-library or cypress. Tests should cover edge cases like empty states, long texts, and internationalized data (RTL, Unicode).
Examples and code resources
To deepen your practical knowledge, follow a hands-on walk-through. A recommended resource is a focused TanStack Table tutorial with real examples and patterns: TanStack Table tutorial. The tutorial demonstrates building powerful data tables in React, including rendering, sorting, and filtering patterns.
Another quick snippet: a sortable column definition uses a header that toggles sorting state:
// Header cell example
<th onClick={() => column.toggleSorting()}>
{column.columnDef.header}
{column.getIsSorted() ? (column.getIsSorted() === "asc" ? " 🔼" : " 🔽") : null}
</th>
Combine these primitives to craft complex UIs: column menus, export buttons, inline editors, and bulk actions. Because you control markup, it's easy to integrate into design systems and style guides.
Further reading & recommended links
If you want additional examples and a walkthrough of building interactive tables, see this practical TanStack Table tutorial. For reference, consult the official TanStack docs for the latest API and patterns.
Pro tip: For server-heavy apps, pair TanStack Table with React Query + an optimized backend paginated API. The combination keeps the UI snappy and the network minimal.
FAQ
How do I install TanStack Table in React?
Install with your package manager: npm i @tanstack/react-table (or yarn/pnpm). Import useReactTable and the row models (getCoreRowModel, getSortedRowModel, etc.) into your React components to initialize and render the table.
How do I implement sorting and filtering with TanStack Table?
Enable the relevant row models (getSortedRowModel, getFilteredRowModel) and manage the sorting and columnFilters state you pass into useReactTable. Update the state on user interactions (header clicks, filter inputs). For large datasets, perform sorting/filtering server-side by controlling state externally and fetching pre-sorted/filtered data.
How do I add pagination and server-side data?
Control pageIndex and pageSize in state and include them in your data-fetch queries (e.g., with React Query). On state changes, fetch the page from the server and update the table's data prop. Use a loading indicator and keep previous data visible to reduce layout jumps.
Leave A Comment