Tables

TanStack Table / AG Grid

Our pick

TanStack Table

It's easy to match your site's look, and it works together with shadcn/ui. If your table has tens of thousands of rows, consider AG Grid

Compare the result

We built the same thing with each library. Try them out.

TanStack Table
AG Grid

Compare the code

Edit the code and the preview on the right updates.

import {
  createColumnHelper,
  createSortedRowModel,
  rowSortingFeature,
  tableFeatures,
  useTable,
} from "@tanstack/react-table"

type Employee = { name: string; department: string; joined: number }

// The data shown in the table
const employees: Employee[] = [
  { name: "Johnson", department: "Sales", joined: 2019 },
  { name: "Brown", department: "Engineering", joined: 2021 },
  { name: "Wilson", department: "Engineering", joined: 2023 },
  { name: "Davis", department: "HR", joined: 2020 },
]

// Features to use (sorting)
const features = tableFeatures({
  rowSortingFeature,
  sortedRowModel: createSortedRowModel(),
})

// Column settings: what each column shows
const helper = createColumnHelper<typeof features, Employee>()
const columns = helper.columns([
  helper.accessor("name", { header: "Name" }),
  helper.accessor("department", { header: "Department" }),
  helper.accessor("joined", { header: "Year joined" }),
])

export default function App() {
  const table = useTable({ features, columns, data: employees })

  return (
    <div className="overflow-hidden rounded-xl border bg-background">
    <table className="w-full text-sm">
      <thead>
        {table.getHeaderGroups().map((group) => (
          <tr key={group.id} className="bg-muted/50">
            {group.headers.map((header) => (
              <th
                key={header.id}
                onClick={header.column.getToggleSortingHandler()}
                className="cursor-pointer px-4 py-2.5 text-left font-medium text-muted-foreground select-none hover:text-foreground"
              >
                <table.FlexRender header={header} />
                {header.column.getIsSorted() === "asc" && " ▲"}
                {header.column.getIsSorted() === "desc" && " ▼"}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody>
        {table.getRowModel().rows.map((row) => (
          <tr key={row.id} className="hover:bg-muted/30">
            {row.getAllCells().map((cell) => (
              <td
                key={cell.id}
                className="border-t px-4 py-2.5"
              >
                <table.FlexRender cell={cell} />
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
    </div>
  )
}

Comparison

As of October 2026

TanStack Table

Our pickOfficial site ↗

Features

Handles only the logic, like sorting and filtering. You write the <table> and styles yourself, so you're free to design it

Best for

You want a table that matches your site's look, e.g. with shadcn/ui. shadcn/ui's Data Table is built with it too

Features

Just pass in data and you get a table with sorting, column resizing, scrolling, and more. Great for Excel-like tables

Best for

Admin screens with very many rows or in-table editing. When features matter more than looks