The useLegacyTable hook provides a compatibility layer that accepts the v8-style API while using v9 under the hood. This is useful for teams that need to migrate incrementally or have large codebases where a full migration isn't immediately practical.
Warning: useLegacyTable is deprecated and intended only as a temporary migration aid. It includes all features by default, resulting in a larger bundle size compared to the tree-shakeable v9 API. Plan to migrate to useTable for better performance and smaller bundles.
import { useState } from 'react'
import { flexRender } from '@tanstack/react-table'
import {
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
legacyCreateColumnHelper,
useLegacyTable,
} from '@tanstack/react-table/legacy'
import type {
ColumnFiltersState,
PaginationState,
SortingState,
} from '@tanstack/react-table'
import type {
LegacyColumn,
LegacyColumnDef,
LegacyRow,
} from '@tanstack/react-table/legacy'
interface Person {
name: string
email: string
age: number
}
const columnHelper = legacyCreateColumnHelper<Person>()
const columns: LegacyColumnDef<Person>[] = [
columnHelper.accessor('name', { header: 'Name' }),
columnHelper.accessor('email', { header: 'Email' }),
columnHelper.accessor('age', { header: 'Age' }),
columnHelper.display({ id: 'actions', header: 'Actions' }),
]
function MyTable({ data }: { data: Person[] }) {
const [sorting, setSorting] = useState<SortingState>([])
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
const [pagination, setPagination] = useState<PaginationState>({
pageIndex: 0,
pageSize: 10,
})
// useLegacyTable accepts the v8-style API
const table = useLegacyTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getSortedRowModel: getSortedRowModel(),
getPaginationRowModel: getPaginationRowModel(),
state: { sorting, columnFilters, pagination },
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onPaginationChange: setPagination,
})
return (
<table>
<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.getCanFilter() ? (
<Filter column={header.column} />
) : null}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getAllCells().map((cell) => (
<td key={cell.id}>
{cell.column.id === 'actions' ? (
<RowActions row={row} />
) : (
flexRender(cell.column.columnDef.cell, cell.getContext())
)}
</td>
))}
</tr>
))}
</tbody>
</table>
)
}
function Filter({ column }: { column: LegacyColumn<Person> }) {
return (
<input
value={(column.getFilterValue() as string) ?? ''}
onChange={(e) => column.setFilterValue(e.target.value)}
placeholder="Filter..."
/>
)
}
function RowActions({ row }: { row: LegacyRow<Person> }) {
return <button onClick={() => console.log(row.original)}>Edit</button>
}
When using useLegacyTable, use these type helpers for proper TypeScript support:
| Type | Description |
|---|---|
| LegacyColumnDef<TData> | Column definition type (equivalent to v8's ColumnDef<TData>) |
| LegacyColumn<TData> | Column instance type |
| LegacyRow<TData> | Row instance type |
| LegacyCell<TData> | Cell instance type |
| LegacyTable<TData> | Table instance type |
| legacyCreateColumnHelper<TData>() | Column helper with StockFeatures pre-bound—only requires TData |
Use legacyCreateColumnHelper instead of createColumnHelper—it has StockFeatures pre-bound, so you only need to specify TData:
import { legacyCreateColumnHelper } from '@tanstack/react-table/legacy'
import type { LegacyColumnDef } from '@tanstack/react-table/legacy'
const columnHelper = legacyCreateColumnHelper<Person>()
const columns: LegacyColumnDef<Person>[] = [
columnHelper.accessor('name', { header: 'Name' }),
// ...
]
While useLegacyTable aims for v8 compatibility, there are a few differences:
The get*RowModel() functions are imported from @tanstack/react-table/legacy:
import {
getCoreRowModel,
getFilteredRowModel,
getSortedRowModel,
getPaginationRowModel,
getExpandedRowModel,
getGroupedRowModel,
getFacetedRowModel,
getFacetedMinMaxValues,
getFacetedUniqueValues,
} from '@tanstack/react-table/legacy'
Note that in v9, sorting-related APIs have been renamed. If you're using custom sorting functions in column definitions:
| v8 | v9 |
|---|---|
| sortingFn | sortFn |
The legacy table adapter handles this internally for built-in sorting, but if you're defining custom sorting functions, be aware of the rename.
useLegacyTable includes all features by default, similar to v8. This means:
useLegacyTable is deprecated and will be removed in a future major version. It exists solely to ease migration. Plan your migration timeline accordingly.
The fine-grained reactivity feature (table.Subscribe) is not available with useLegacyTable. The table re-renders on every state change, like v8.
useLegacyTable cannot be used with createTableHook. If you want to create reusable table configurations, migrate to the full v9 API.
Once you're ready to migrate to the full v9 API:
See the main migration guide for complete instructions.
See the Basic useLegacyTable example for a working implementation.