Episode ini membangun tabel pertama dengan TanStack Table: mendefinisikan kolom lewat columnHelper, memakai useReactTable dengan row model, merender sel dengan flexRender, lalu menambahkan sorting, filtering, dan pagination.

TanStack Query mengelola data server; TanStack Table mengelola cara data itu ditampilkan dalam baris dan kolom. Setelah episode 5, kalian punya data dari query — sekarang waktunya menyajikannya dalam tabel yang bisa di-sort, di-filter, dan di-paginate.
Episode 6 membangun tabel pertama dari nol: mendefinisikan kolom sebagai data, memakai useReactTable, merender lewat flexRender, lalu mengaktifkan sorting, filtering, dan pagination lewat row model.
Penting diingat dari episode 2: TanStack Table tidak menyediakan gaya visual. Kalian yang merender tabel dengan elemen HTML biasa — inilah filosofi headless dalam bentuk paling nyata.
Kolom didefinisikan sebagai data dengan createColumnHelper. Tipe data diberikan sebagai generic agar aksesor ter-check oleh TypeScript:
import { createColumnHelper } from "@tanstack/react-table"
type Pengguna = { id: number; nama: string; peran: string }
const data: Pengguna[] = [
{ id: 1, nama: "Arman", peran: "Engineer" },
{ id: 2, nama: "Dwi", peran: "Designer" },
]
const columnHelper = createColumnHelper<Pengguna>()
const columns = [
columnHelper.accessor("id", { header: "ID" }),
columnHelper.accessor("nama", { header: "Nama" }),
columnHelper.accessor("peran", { header: "Peran" }),
]createColumnHelper<Pengguna>() mengikat helper ke tipe data, sehingga columnHelper.accessor("nama" divalidasi oleh compiler. header adalah label kolom; nanti bisa diganti fungsi atau komponen.
useReactTable menerima data, kolom, dan satu atau lebih row model. Model dasar adalah getCoreRowModel:
import { useReactTable, getCoreRowModel } from "@tanstack/react-table"
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
})useReactTable({ data, columns }) membangun core table. getCoreRowModel() menghitung baris dasar. Model lain — sorting, filtering, pagination — tinggal ditambahkan di daftar yang sama.
Rendering memakai table.getHeaderGroups(), table.getRowModel().rows, dan flexRender untuk memanggil definisi header dan cell:
<table>
<thead>
{table.getHeaderGroups().map((hg) => (
<tr key={hg.id}>
{hg.headers.map((header) => (
<th key={header.id}>
{flexRender(header.column.columnDef.header, header.getContext())}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>flexRender(header.column.columnDef.header, header.getContext()) mengevaluasi definisi header menjadi elemen nyata. header.getContext() dan cell.getContext() membawa state tabel yang dibutuhkan cell — inilah jembatan antara definisi dan hasil render.
Tiga fitur dasar diaktifkan hanya dengan menambahkan model ke useReactTable:
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
})
const { pageIndex, pageSize } = table.getState().paginationModel diproses berurutan: core menghasilkan baris, filter menyaringnya, sorting mengurutkannya, pagination memotongnya menjadi halaman. table.getState().pagination berisi halaman aktif dan ukuran halaman.
Sorting diaktifkan lewat tombol pada header, pagination lewat tombol pindah halaman:
<button onClick={header.column.getToggleSortingHandler()}>
{header.column.getIsSorted() === "asc" ? "Naik" : "Turun"}
</button><button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
Sebelumnya
</button>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
Berikutnya
</button>header.column.getToggleSortingHandler() membalik arah sorting saat diklik. table.previousPage() dan table.nextPage() memindahkan halaman, sementara getCanPreviousPage dan getCanNextPage menonaktifkan tombol di ujung rentang.
Info
Filtering dasar bisa diaktifkan dengan column.setFilterValue lewat input pada setiap header. Episode 9 akan membahas filtering lanjutan, grouping, dan kolom dinamis.
Episode 6 menyelesaikan tabel pertama: kolom didefinisikan sebagai data dengan columnHelper, useReactTable menggabungkan data dan row model, rendering dilakukan manual dengan flexRender, lalu sorting, filtering, dan pagination aktif lewat model tambahan.
Inti yang harus dibawa pulang:
Di episode 7 selanjutnya kita akan membahas routing dan navigation — membangun route tree dengan TanStack Router, nested routes dan layout, data loading dengan loader, serta navigasi dengan Link dan state route. Kalian akan menghubungkan tabel episode 6 ke URL yang benar-benar bisa dinavigasi!