
TanStack Table - flexible and powerful tables in React
Creating advanced tables in web applications is one of those tasks that on the surface seems simple - until the user expects sorting, filtering, pagination, grouping, flexible styling and performance with thousands of rows of data. Then it turns out that classic table components can't keep up with design and business needs. In this article, I'll show you what TanStack Table is, how the headless approach works, how it differs from traditional component libraries, and how to create a fully functional yet customized table with its help, step by step. Whether you are developing an analytics dashboard, CMS system or business application, TanStack Table can become one of your most important tools.

- 1. What is the TanStack Table?
- 1.1. Headless UI – what does it actually mean?
- 1.2. Framework-agnostic philosophy
- 2. When should you use TanStack Table in your project?
- 3. Examples of TanStack Table’s most important features
- 3.1. Data sorting
- 3.2. Data filtering
- 3.3. Pagination
- 3.4. Data grouping
- 3.5. Data aggregation
- 3.6. Virtualization
- 3.7. Column customization
- 3.8. Styling and integration with UI systems
- 4. Creating your first table with TanStack Table
- 5. Summary
- 6. FAQ – Frequently asked questions about TanStack Table
- 6.1. How is TanStack Table different from component libraries (e.g., AG Grid, MUI Table)?
- 6.2. Does TanStack Table only work with React?
- 6.3. Do I need additional libraries to run TanStack Table?
- 6.4. Can I use TanStack Table with TailwindCSS, MUI, or my own design system?
- 6.5. Is TanStack Table suitable for large production projects?
What is the TanStack Table?
TanStack Table (formerly known as React Table) is an advanced JavaScript library for building dynamic, fully customizable tables and data grids (data grids). Its biggest differentiator is that it runs on a headless UI model – meaning that it provides only logic, state management and interaction tools, without imposing HTML structure or CSS styles.
Headless UI – what does it actually mean?
Traditional component libraries (e.g. AG Grid or Material UI Table) offer ready-made components with imposed structure and appearance. This works well, as long as you don’t need full control over the look or integration with your own design system. TanStack Table goes in the opposite direction: it lets you completely decide how your table looks and behaves – while taking responsibility for the hardest parts: state management, data processing, sorting, filtering or pagination.
In practice, this means that TanStack Table does not render anything for you. Instead, it gives you access to ready-made logic that you can embed in your components as you see fit. This allows you to create tables:
- with your own HTML tags or UI components,
- styled using TailwindCSS, Styled Components, CSS-in-JS, or any other method,
- which are fully accessible (a11y) and optimized for performance.
Framework-agnostic philosophy
Although TanStack Table started life as a library strictly for React, today it also supports other frontend frameworks such as Vue, Svelte, Solid, and Qwik. This makes it a future-proof solution – no matter what technology you choose for your next project, TanStack Table’s approach and API will remain familiar.
When should you use TanStack Table in your project?
TanStack Table is particularly useful when:
– You want full control over the appearance of the table: whether you use Tailwind, MUI, Chakra UI, or your own styling system, TanStack Table imposes no restrictions. You decide on the HTML and CSS structure.
– you are integrating with a non-standard design system (Design System). Do you have a corporate design system or do you need to strictly adhere to client guidelines? TanStack Table will fit right in, as it does not enforce any predefined styles or components.
– Need efficient handling of large data sets? Thanks to virtualization support and intelligent state management, the library can handle tables with thousands of rows without slowing down the interface.
-Do you require flexibility when implementing complex interactive features: data grouping, expandable rows, drag-and-drop columns, custom cell editors? You can build all of this on top of TanStack Table’s logic – without compromise.
Examples of TanStack Table’s most important features
TanStack Table is a library that does not provide ready-made components – but it gives you all the tools you need to build exactly the table you need. Below you will find key features with practical examples of their use in React.
1. Data sorting
Sorting is one of the most common functions in a table. In TanStack Table, you can easily enable column sorting. Example:
import {
useReactTable,
getCoreRowModel,
getSortedRowModel,
} from '@tanstack/react-table'
const table = useReactTable({
data,
columns,
state: {
sorting,
},
onSortingChange: setSorting,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
})
Just click on the column header to change the sort order. You can also create your own sort icons and logic for data types (e.g., dates, numbers, text).
2. Data filtering
You can add both global filtering and individual column filtering – all with your own UI. Below is an example of text filtering for a column:
{
accessorKey: 'email',
header: 'Email',
filterFn: 'includesString',
}
Custom filter field component:
<input
value={table.getColumn('email')?.getFilterValue() ?? ''}
onChange={(e) =>
table.getColumn('email')?.setFilterValue(e.target.value)
}
/>
3. Pagination
TanStack Table supports both local and server-based paging – depending on your data source. Example (local):
const table = useReactTable({
pageCount: -1, //
manualPagination: true,
onPaginationChange: setPagination,
getPaginationRowModel: getPaginationRowModel(),
})
Pages, counter, “next/previous” – you can implement any interface you want.
4. Data grouping
You can group rows by one or more columns, creating a nested data structure. Example:
{
accessorKey: 'department',
enableGrouping: true,
}
The result: data is grouped by department
, and each group can be expanded/closed dynamically.
5. Data aggregation
Aggregation is an extremely useful feature, especially in the context of analytical, financial, or reporting applications. It allows you to automatically summarize values in columns—for example, calculate total sales, average rating, number of reports, or maximum value.
TanStack Table allows you to assign your own aggregation function to a column (e.g., sum
, average
, count
, max
, min
, or a completely custom function) and define how a given column should behave in a group row.
Below is an example of summing salaries by department:
{
accessorKey: 'salary',
header: 'Salary',
aggregationFn: 'sum', // aggregation function
aggregatedCell: ({ getValue }) => `Suma: $${getValue()}`, // group row view
}
In combination with the grouping feature, TanStack Table will automatically sum all salary
values for each department
and display the summary in the group. Why is this important? Because it makes it easy to present aggregate data without additional server-side logic. You can easily extend the table UI with summary rows, section summaries, or even multi-level aggregates. In addition, you have full control over the presentation format of aggregated data – you can highlight it graphically, color it, add icons, etc.
This feature works particularly well in dashboards, reports, online spreadsheets, and ERP/CRM systems.
6. Virtualization
If your table contains thousands of rows, you can use @tanstack/react-virtual
to render only the visible elements, significantly improving performance. For example, instead of rendering 10,000 rows, only the 30 currently visible rows are rendered.
7. Column customization
One of the biggest advantages of TanStack Table is that it gives you complete freedom to define, modify, and manage columns – both during table configuration and dynamically during application runtime. This is extremely useful in projects where the interface needs to adapt to user roles, preferences, or business context. Below we show dynamic columns based on a condition:
const userColumns = showSalary
? [...baseColumns, salaryColumn]
: baseColumns
In this example, the “salary” column will only be visible if showSalary
returns true
– for example, if the user has permission to see salary data.
What can you do with column personalization? E.g.: based on application status, user role or filter, you can hide or show a column. You can let users drag (drag-and-drop) columns to rearrange the table according to their preferences. What else? You can save your column configuration (e.g., visibility, width, order) to a localStorage, database or user profile – and restore it with each session. Here’s an example: setting custom headers and widths:
{
accessorKey: 'createdAt',
header: () => <span>Date of creation</span>,
size: 180,
}
8. Styling and integration with UI systems
TanStack Table stands out because it does not impose any styling or HTML structure on you. Unlike ready-made components from libraries such as Material UI or Bootstrap, TanStack Table allows you to define every element of the table yourself: from <table>
, through <thead>
and <tbody>
, to cells, sorting buttons, pagination, and even loading spinners.
This approach gives you complete freedom to integrate with any UI design system – no friction, no rework, no fighting with style overrides.
TailwindCSS works great with TanStack Table. Thanks to utility classes, you can style every table element with precision without the need to create additional components. For example:
<table className="min-w-full divide-y divide-gray-200">
<thead className="bg-gray-50">
<tr>
{table.getHeaderGroups().map(headerGroup =>
headerGroup.headers.map(header => (
<th
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
key={header.id}
>
{header.column.columnDef.header}
</th>
))
)}
</tr>
</thead>
</table>
In the example above, the table headers are fully controlled and styled using Tailwind – but you could just as easily use your own CSS classes or any other styling system. Regardless of how you style your application, TanStack Table supportsany custom components with rendering logic: TailwindCSS, CSS Modules, Styled Components / Emotion, Vanilla CSS, UI frameworks (MUI, Chakra, Bootstrap).
Creating your first table with TanStack Table
To see for yourself how amazing TanStack Table is, we recommend that you start your first project. In a few steps, we will show you how to create your first table.
1. Install the necessary packages:
npm install @tanstack/react-table
If you plan to handle large data sets and are concerned about performance, it’s also worth adding virtualization:
npm install @tanstack/react-virtual
2. Create a basic table – suppose you have user data. Let’s start with data and column definitions:
const data = [
{ id: 1, name: 'Anna', email: 'anna@example.com' },
{ id: 2, name: 'Tom', email: 'tomasz@example.com' },
]
const columns = [
{
accessorKey: 'name',
header: 'Name',
},
{
accessorKey: 'email',
header: 'Email',
},
]
Next, we initialize the table:
import { useReactTable, getCoreRowModel } from '@tanstack/react-table'
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
})
Now we are rendering the table:
<table>
<thead>
{table.getHeaderGroups().map(headerGroup => (
<tr key={headerGroup.id}>
{headerGroup.headers.map(header => (
<th key={header.id}>
{/* Use flexRender, if you want to render custom components or JSX */}
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map(row => (
<tr key={row.id}>
{row.getVisibleCells().map(cell => (
<td key={cell.id}>
{/* 🧠 To samo dotyczy komórek danych – flexRender obsłuży komponenty, JSX, tekst, liczby itd. */}
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</td>
))}
</tr>
))}
</tbody>
</table>
Use flexRender
instead of a direct call to .renderCell()
. flexRender()
is a function created by the authors of TanStack Table that supports both simple values (e.g. string, number) and JSX rendering functions. With it, you can use e.g. () => <span>{value}</span>
in columns without the risk that the table will return [Object Object]
or nothing.
Each header
and cell
can be a rendering function. In column definition, you can use functions in header
and cell
, for example:
{
accessorKey: 'email',
header: () => <span>Email 📧</span>,
cell: ({ getValue }) => (
<a href={`mailto:${getValue()}`} className="text-blue-600 underline">
{getValue()}
</a>
)
}
Then we move on to point 3, which is to add extensions to the logic:
import {
getSortedRowModel,
getFilteredRowModel,
getPaginationRowModel,
} from '@tanstack/react-table'
const table = useReactTable({
data,
columns,
state: {
sorting,
pagination,
columnFilters,
},
onSortingChange: setSorting,
onPaginationChange: setPagination,
onColumnFiltersChange: setColumnFilters,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
Add a UI for sorting (e.g., click on the header):
<th
onClick={header.column.getToggleSortingHandler()}
>
{header.column.columnDef.header}
{header.column.getIsSorted() === 'asc' ? ' 🔼' : ' 🔽'}
</th>
Then we add a simple filter:
<input
value={table.getColumn('name')?.getFilterValue() ?? ''}
onChange={e =>
table.getColumn('name')?.setFilterValue(e.target.value)
}
/>
and pagination buttons:
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
Previous
</button>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
next
</button>
4. Customize the table appearance. Here, you have complete freedom. You can use Tailwind, Styled Components, MUI, or classic CSS. Below is an example using Tailwind CSS.
<table className="min-w-full table-auto border border-gray-200">
<thead className="bg-gray-100">
<tr>
{table.getHeaderGroups().map(headerGroup => (
headerGroup.headers.map(header => (
<th
key={header.id}
className="px-4 py-2 text-left font-semibold text-sm text-gray-600"
>
{header.column.columnDef.header}
</th>
))
))}
</tr>
</thead>
</table>
Congratulations! You have just created your first fully functional table using TanStack Table – with custom data, sorting, filtering and pagination. From now on, you have a foundation on which to build more advanced and customized solutions for your project.
Summary
TanStack Table is a tool that perfectly meets the needs of modern frontend teams: it offers maximum flexibility, full control, and tremendous scalability—without imposing any stylistic or architectural constraints.
Unlike ready-made component libraries, which often offer a lot but come with difficult-to-work-around limitations, TanStack Table works in a “headless-first” spirit. This means that everything you see in the interface – style, markup, interactions – is created by you, and the library is only responsible for the really difficult stuff: logic, state, performance, and data processing.
FAQ – Frequently asked questions about TanStack Table
1. How is TanStack Table different from component libraries (e.g., AG Grid, MUI Table)?
TanStack Table is a headless UI library – it does not provide ready-made components or styles. Instead, it gives you the full table management logic (sorting, filtering, pagination, grouping, etc.), and you create the look and HTML structure yourself. This is ideal when you want full control over the user interface.
2. Does TanStack Table only work with React?
No! Although it is most commonly used in React projects, TanStack Table also supports other frontend frameworks such as Vue, Svelte, Solid, and Qwik. Each version has a dedicated API tailored to the specifics of the framework.
3. Do I need additional libraries to run TanStack Table?
No, @tanstack/react-table
is all you need to get started. If you care about performance with large data sets, you can install @tanstack/react-virtual
, which enables virtualization (rendering only visible rows).
4. Can I use TanStack Table with TailwindCSS, MUI, or my own design system?
Yes, and that’s its biggest advantage. TanStack Table doesn’t impose any styling, which means you can freely integrate it with any CSS system: Tailwind, Styled Components, Emotion, Material UI, Bootstrap – even your own design system.
5. Is TanStack Table suitable for large production projects?
Absolutely. It is a mature, stable, and highly performant library used in many professional applications. Thanks to its modularity, light weight, and flexible API, it works great in large systems: from admin panels to analytics apps to advanced B2B tools.


