shadcn Table Generator
Simple tables and data tables, for both TanStack APIs.
| Status↕ | Email↕ | Amount |
|---|---|---|
| success | ken99@example.com | $316.00 |
| pending | abe45@example.com | $242.00 |
| processing | monserrat44@example.com | $837.00 |
| failed | carmella@example.com | $721.00 |
"use client"
import { createColumnHelper } from "@tanstack/react-table"
import type { DataTableFeatures } from "./data-table-features"
export type Row = {
status: string
email: string
amount: number
}
const columnHelper = createColumnHelper<DataTableFeatures, Row>()
export const columns = columnHelper.columns([
columnHelper.accessor("status", {
header: ({ column }) => (
<Button variant="ghost" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
Status
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
),
cell: ({ row }) => <Badge variant="outline">{row.getValue("status")}</Badge>,
}),
columnHelper.accessor("email", {
header: ({ column }) => (
<Button variant="ghost" onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}>
Email
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
),
}),
columnHelper.accessor("amount", {
header: () => <div className="text-right">Amount</div>,
cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount"))
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(amount)
return <div className="text-right font-medium">{formatted}</div>
},
}),
])
The version split is the hard part
Two things make shadcn tables confusing. The first is that "table" means two different components — styled markup, or a TanStack-powered data table. The second is that TanStack Table changed its API in v9, so most tutorials and most installed projects disagree with the current docs. This handles both, and tells you which is which.
How to use it
-
Pick simple or data table
Simple is styled markup with no behaviour. Data table adds TanStack Table for sorting, filtering, pagination and selection.
-
Check your TanStack version
v9 is current and what the shadcn docs show; v8 is still the more widely installed. The generator emits either — look at your package.json first.
-
Define the columns
accessorKey, header text, cell type and alignment. Currency columns get an Intl formatter, badge columns get a Badge.
-
Turn on the features you need
Each one adds its imports, its state and its row model. Nothing is included that you did not ask for.
-
Copy each file
The data table comes as columns.tsx, data-table.tsx and — on v9 — a data-table-features.ts.
v9 and v8 are genuinely different
v9 is the current release. It uses useTable, a separate
data-table-features.ts composed with tableFeatures(), and renders
cells with <table.FlexRender />. v8 uses useReactTable, passes
row-model functions like getSortedRowModel() inline, and renders with the
flexRender() helper. Code written for one will not run on the other, and v8 is
still what most projects have installed. Check package.json before you copy.
Every feature needs its row model
The most common data-table bug is registering a feature and forgetting its row model. Sorting
state updates, the header arrow flips, and the rows never move — because
getSortedRowModel() (v8) or createSortedRowModel() (v9) was never
wired in. Toggling a feature here adds both halves.
Sticky headers need a background
sticky top-0 alone leaves the header transparent, so rows scroll visibly through
the text. It needs bg-background and a scroll container with a real max height —
the sticky header option sets up all three.
Placing the table on the page
A data table usually lives inside an app shell. Pair it with the sidebar generator for the navigation and the dashboard layout for the region that scrolls.
Frequently asked questions
What is the difference between the shadcn table and data table?
Table component is styled markup — TableHeader, TableRow, TableCell — with no behaviour. The data table adds TanStack Table on top for sorting, filtering, pagination and selection. Use the plain one for static content; reach for the data table only when you need the interaction.Which TanStack Table version does shadcn use?
latest release. v9 uses useTable with a tableFeatures file; v8 uses useReactTable with row-model functions like getSortedRowModel(). v8 is still very widely installed, so check your package.json — this generator emits either.How do I make a sticky table header?
overflow-auto, then give TableHeader className="sticky top-0 bg-background". The background matters: without it, rows scroll visibly behind the header.How do I add sorting to a shadcn table?
column.toggleSorting(column.getIsSorted() === "asc"). In v8 you also add getSortedRowModel() and a SortingState; in v9 you include rowSortingFeature and createSortedRowModel() in your features file.How do I add row selection with checkboxes?
select whose header renders a checkbox bound to table.getIsAllPageRowsSelected() and whose cell binds to row.getIsSelected(). Set data-state={row.getIsSelected() && "selected"} on the row so it styles correctly.Why is my data table not filtering or sorting?
getFilteredRowModel(), getSortedRowModel() — passed to useReactTable. In v9 the equivalent models go in tableFeatures. Without them the state updates and the rows never change.