cssgridgen

shadcn Table Generator

Simple tables and data tables, for both TanStack APIs.

Filter status
StatusEmailAmount
success[email protected]$316.00
pending[email protected]$242.00
processing[email protected]$837.00
failed[email protected]$721.00
PreviousNext
"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>
    },
  }),
])
Free tool

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

  1. Pick simple or data table

    Simple is styled markup with no behaviour. Data table adds TanStack Table for sorting, filtering, pagination and selection.

  2. 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.

  3. Define the columns

    accessorKey, header text, cell type and alignment. Currency columns get an Intl formatter, badge columns get a Badge.

  4. 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.

  5. 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?
The 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?
The current docs use v9, which is the 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?
Put the table in a container with a max height and 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?
Make the column header a button that calls 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?
Add a display column with id 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?
The feature is registered but the row model is missing. In v8 every feature needs its function — getFilteredRowModel(), getSortedRowModel() — passed to useReactTable. In v9 the equivalent models go in tableFeatures. Without them the state updates and the rows never change.