TanStack Table for React: Setup, Tutorial & Examples
Quick answer: TanStack Table is a headless, composable, high-performance table (data grid) library for React. It provides hooks and utilities for sorting, filtering, pagination and virtualization while leaving rendering and styling to you. Use it when you need a flexible, framework-agnostic data table that integrates with React patterns and custom UIs.
Why TanStack Table (and what “headless” actually means)
TanStack Table is intentionally headless: it exposes a small set of hooks and utilities to build powerful data tables but does not impose markup or styles. That design gives you full control over DOM, accessibility attributes, and visual design. The trade-off is boilerplate for markup, but the reward is unmatched flexibility when you need custom cell renderers, nested rows, or accessible ARIA patterns.
For teams building product-grade apps, that flexibility matters. You can implement a minimal table for admin panels, or a fully interactive grid with virtual scrolling, column-resizing, and custom cell editors while keeping logic testable and decoupled from presentation.
If you’ve used older table libraries that force markup or heavy CSS, TanStack feels different: smaller runtime, hooks-first API, and an emphasis on composable primitives. For a canonical reference, see the official docs and examples (linked later).
Installation and Setup
Start by installing the package. With npm or yarn the install is a single command: npm i @tanstack/react-table (or yarn add @tanstack/react-table). You only get the table engine — rendering components are yours to create, keeping bundle size predictable.
Typical setup uses the useReactTable hook to create the table instance, passing columns, data, and plugins (sorting, filtering, pagination). The table instance exposes methods and row/column models that you map to your JSX for headers, body rows, and cells.
Example baseline install and imports (condensed):
npm i @tanstack/react-table
// in component:
import { useReactTable, getCoreRowModel } from '@tanstack/react-table'
Links: TanStack Table docs, GitHub repo, and a practical walkthrough on Dev.to: Building Powerful Data Tables with TanStack Table in React.
Core concepts: columns, rows, row model, and the headless API
Columns in TanStack Table are declarative objects describing accessors, headers, cell renderers, and metadata. The engine uses columns to build a column model and to compute row models for rendering. Accessors can be strings or functions; cell renderers are where you inject JSX and custom controls.
The table’s row model is computed via plugins: getCoreRowModel is the base; add getSortedRowModel, getFilteredRowModel, and getPaginationRowModel to layer features. Each model returns memoized data structures so rendering remains fast even with many rows.
Because rendering is decoupled, you control ARIA attributes, keyboard navigation, and virtualization strategy (for example with react-virtual or your own windowing). That makes TanStack Table fit both small UIs and high-performance grids.
Sorting, Filtering, and Pagination
Sorting is enabled by adding sorting state and handlers to useReactTable. Each column can enable sorting and provide a custom sortFn. The table then exposes toggleSortBy methods you wire to header click handlers and arrow icons.
Filtering follows a similar pattern: column-level filters, filterFns, and a global filter option. You can implement client-side filters quickly; for very large datasets it’s common to handle filtering on the server and push results back to the table via controlled props.
Pagination is conceptually simple: use getPaginationRowModel and control pageIndex/pageSize state. For remote pagination, you fetch slices of data and feed them into the table while keeping UI controls tied to your external state.
- Sorting: toggle per column, custom sort functions.
- Filtering: column or global filters, server-side option.
- Pagination: client or server paging with pageIndex/pageSize control.
Interactive tables: cell actions, editors, selection
Interactivity is where TanStack Table shines. Since you render cells, adding buttons, inline editors, or context menus is straightforward: render components inside cell renderers and use row metadata to manage state. For example, an inline input can call an update handler that updates local or remote data and then triggers a table refresh.
Selection (single/multi) is commonly implemented by augmenting row objects with an isSelected flag or by using a separate selectedIds map in your component state. The table instance can help by exposing row.id and other helpers so you avoid brittle DOM queries.
Editor components can be built as controlled or uncontrolled inputs. For better UX, debounce saves and optimistic updates when saving to an API. Because TanStack Table doesn’t impose structure, you choose the UX pattern that fits your app.
Performance and best practices
TanStack Table is designed with memoization and small runtime overhead. Still, performance dips if you re-create column or data references on every render. Memoize columns and data using useMemo to keep table hooks stable and avoid unnecessary recomputation.
For very large datasets, combine server-side pagination/filtering with a virtualization library (e.g., @tanstack/react-virtual or react-window). Keep heavy computations off the render path — pre-compute derived fields where possible.
Keep column definitions lean: move custom render logic to separate components. Use stable keys for rows and avoid anonymous functions in props that run every render without need.
- Memoize columns and data (useMemo).
- Use virtualization for large lists.
- Prefer server-side for huge datasets.
Example: building a simple interactive table
Below is a condensed example showing setup, columns, and a basic render with sorting and pagination enabled. This is not a drop-in but a clear skeleton you can adapt.
import React, { useMemo, useState } from 'react'
import { useReactTable, getCoreRowModel, getSortedRowModel, getPaginationRowModel } from '@tanstack/react-table'
function MyTable({ data }) {
const [sorting, setSorting] = useState([])
const [pageIndex, setPageIndex] = useState(0)
const [pageSize, setPageSize] = useState(10)
const columns = useMemo(() => [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'Name', enableSorting: true },
{ accessorKey: 'email', header: 'Email' },
], [])
const table = useReactTable({
data,
columns,
state: { sorting, pagination: { pageIndex, pageSize } },
onSortingChange: setSorting,
onPaginationChange: updater => {
const next = typeof updater === 'function' ? updater({ pageIndex, pageSize }) : updater
setPageIndex(next.pageIndex)
},
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
return (
// render headers, rows, pager using table.getRowModel(), table.getHeaderGroups(), etc.
)
}
Adapt the render block to your UI library: plain table, div-based grid, or a design system. The engine remains the same.
For a full, production-ready example, consult the official examples and the community article linked earlier.
When to choose TanStack Table vs other React data grid libraries
Choose TanStack Table when you need flexibility, small runtime, and control over rendering and accessibility. It’s excellent for bespoke UIs, complex interactions, and apps where you own design system components.
If you need a batteries-included grid with built-in virtualization, cell editing, column resizing, and a full-featured UI out of the box, consider a commercial grid (e.g., AG Grid) or opinionated libraries that provide components and styles. Those can reduce development time at the cost of opinionated markup and larger bundles.
In short: TanStack Table for control and composition; other grids for turn-key features and fast integration.
Semantic core (expanded keyword clusters)
Primary keywords
TanStack Table React, TanStack Table tutorial, React table TanStack, TanStack Table installation, React data table headless
Secondary / mid-frequency keywords
TanStack Table example, React table component, TanStack Table setup, React interactive table, TanStack Table sorting
Supporting / long-tail and LSI phrases
React data grid, TanStack Table filtering, React table library, TanStack Table pagination, React table component tutorial, headless data table React, useReactTable hook, getCoreRowModel, server-side pagination tanstack, custom cell renderer tanstack
Clusters
Core setup: TanStack Table installation, TanStack Table setup, useReactTable hooks.
Features: TanStack Table sorting, TanStack Table filtering, TanStack Table pagination, React interactive table.
Implementation & examples: TanStack Table example, React table component tutorial, React data table headless.
Alternatives & comparisons: React data grid, React table library, AG Grid vs TanStack.
FAQ — top user questions
Q1: Is TanStack Table a full UI component or headless library?
A1: TanStack Table is headless — it provides hooks and logic without rendering components. You build the markup and styling, which gives flexibility but requires more initial setup than componentized grids.
Q2: How do I add sorting and filtering?
A2: Enable sorting/filtering by adding state and the corresponding row model plugins (getSortedRowModel, getFilteredRowModel). Define column-level options like enableSorting and filterFn, and wire header controls to table.toggleSorting/ setFilter handlers.
Q3: Can I use TanStack Table with server-side pagination?
A3: Yes. Use controlled pagination state (pageIndex, pageSize) and fetch data slices from your API. Keep table state in your component and update data when pagination or filters change.
Outbound links & references (backlinks using keywords)
Official docs: TanStack Table React
GitHub: React data table headless (GitHub)
Community tutorial: TanStack Table tutorial — Dev.to walkthrough
SEO & publishing checklist
Recommendations before publishing: ensure columns/data are memoized, include canonical URL, add Open Graph tags if sharing on social, and test FAQ schema with Google Rich Results Test. Use concise H1 and H2s, include at least one code example and external links to authoritative docs (done above).
Optimize for voice search by keeping short answer snippets near the top and using conversational Q&A phrasing (the quick answer and FAQ sections are intended for that purpose).
If you want, I can also output a trimmed version for AMP, or provide additional microdata for Article schema.