TanStack Table logo

TanStack Table

A headless, framework-agnostic library for building powerful tables and datagrids with 100% control over markup and styles.

npm install @tanstack/react-table
27.3K5.2M/weekv8.21.3744.03 KBMIT333 issues
Last updated: 2025-04-15
Star history chart for TanStack/table

TL;DR

Headless UI: A utility belt for table logic (sorting, filtering, grouping) that provides no markup or styles, leaving the rendering entirely to you.

Ecosystem Standard: The successor to React Table, now rewritten in TypeScript to be framework-agnostic while maintaining a first-class React adapter.

Why TanStack Table?

TanStack Table (formerly React Table) flips the traditional component library model on its head. Instead of giving you a <Table /> component that is hard to customize, it gives you a useReactTable hook that manages the complex state of data grids—sorting, filtering, pagination, and aggregation—while you write the <table>, <div>, or <li> tags yourself.

  • True Headless Architecture: Zero inherent styling or markup. You bring the UI library (MUI, Tailwind, AntD) or your own custom CSS.
  • Framework Agnostic Core: The logic lives in a framework-agnostic core, ensuring stability and shared improvements across React, Vue, Solid, and Svelte.
  • Performance First: Designed to handle thousands of rows without breaking a sweat, with easy integration for virtualization (via TanStack Virtual).
  • First-Class TypeScript: Written in TypeScript with complex generics to ensure your data accessors and column definitions are strictly typed.
  • Feature Density: Out-of-the-box support for multi-sorting, global filtering, column resizing, row selection, and nested headers.

Code Snippet

This snippet demonstrates the v8 API, using createColumnHelper for type safety and flexRender to handle custom cell components.

import {
  useReactTable,
  getCoreRowModel,
  flexRender,
  createColumnHelper,
} from '@tanstack/react-table';

// 1. Define your data type
type User = {
  id: number;
  name: string;
  email: string;
};

const columnHelper = createColumnHelper<User>();

// 2. Define columns with the helper for type safety
const columns = [
  columnHelper.accessor('name', {
    header: 'Full Name',
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor('email', {
    header: 'Email Address',
    cell: (info) => <span className="italic">{info.getValue()}</span>,
  }),
];

export function UserTable({ data }: { data: User[] }) {
  // 3. Initialize the table instance
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(), // Essential for basic row rendering
  });

  // 4. Render utilizing your own markup
  return (
    <table className="w-full border-collapse">
      <thead>
        {table.getHeaderGroups().map((headerGroup) => (
          <tr key={headerGroup.id}>
            {headerGroup.headers.map((header) => (
              <th key={header.id} className="border p-2 text-left">
                {header.isPlaceholder
                  ? null
                  : flexRender(
                      header.column.columnDef.header,
                      header.getContext()
                    )}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody>
        {table.getRowModel().rows.map((row) => (
          <tr key={row.id} className="hover:bg-gray-50">
            {row.getVisibleCells().map((cell) => (
              <td key={cell.id} className="border p-2">
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
}

In this example, flexRender delegates the rendering logic. If a header is a simple string, it renders it; if it's a React component, it mounts it. This pattern keeps the API consistent regardless of column complexity.

Pros and Cons

No library is perfect; understanding the trade-offs is key to selecting the right tool.

Pros

  • Absolute Design Control: You will never have to use !important to override a library's default CSS because there is no default CSS.
  • Small Bundle Size: Because it doesn't ship with UI components, it is significantly lighter than alternatives like AG Grid or MUI DataGrid.
  • Deep Customization: Every aspect of the table logic (sorting algorithms, filter functions) is replaceable.
  • Type Inference: The generic typing for columns and data is best-in-class, catching property access errors at compile time.

Cons

  • High "Boilerplate" Setup: You cannot just drop it in and see a table. You must write the loop for headers, rows, and cells yourself.
  • No Built-in UI: Features like "Column Menu," "Date Picker Filter," or "Pagination Controls" must be built by you using the state exposed by the hook.
  • Learning Curve: The API is abstract. Concepts like "Cell Context" and "Column Helpers" require reading the docs.

Comparison with Other Table Libraries

The table below outlines the positioning differences between TanStack Table and other popular table libraries to help you make an informed decision:

LibraryDesign PhilosophyBest ForPain Points
TanStack TableHeadless Logic
Logic-only hook; you own the DOM.
Custom Designs
Design systems where pixel-perfect control is mandatory.
Setup Time
Requires wiring up every HTML element manually.
MUI X DataGridBattery-Included
Full Material Design component.
Enterprise Dashboards
Rapid development where Material UI is already used.
Styling Overrides
Hard to break out of the Material Design look.
AG GridExcel on Web
Massive feature set, canvas-like performance.
Financial Data
Handling 100k+ rows with Excel-like features (pivoting, clipboard).
Bundle Size
Very heavy; complex licensing for enterprise features.

Ecosystem & Extensions

TanStack Table is part of a larger ecosystem designed to work together:

  • TanStack Virtual: Essential for rendering massive datasets (10k+ rows) by only rendering visible DOM nodes.
  • TanStack Query: The de-facto standard for fetching the data that populates your tables.
  • Material React Table / Mantine React Table: Third-party wrappers that combine TanStack Table logic with UI libraries if you decide you want a pre-built solution later.