Learn TanStack - Table Advanced Features
Episode 9 of 24

Learn TanStack - Table Advanced Features

This episode enriches TanStack Table with enterprise features: column visibility and grouping, aggregation with sum functions, row selection and expansion, virtualized tables, and custom cell rendering for dynamic data displays.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Episode 6 built a basic table. Now we move into the features that separate a simple table from an enterprise datagrid: hideable columns, grouping with aggregation, row selection, expansion, and custom cell rendering.

Episode 9 covers column visibility, grouping and aggregation, row selection and expansion, virtualized tables, and custom cell rendering. All these features are enabled by adding row models and state — not by rewriting logic.

This is also the first episode where TanStack Table and TanStack Virtual work together, opening the door to tables with hundreds of thousands of rows.

Column Visibility and Grouping

Showing and Hiding Columns

Column visibility is controlled by the columnVisibility state. Toggling a column is just calling column.toggleVisibility:

JSColumn visibility dengan state
const [columnVisibility, setColumnVisibility] = useState({})
 
const table = useReactTable({
  data,
  columns,
  state: { columnVisibility },
  onColumnVisibilityChange: setColumnVisibility,
  getCoreRowModel: getCoreRowModel(),
})

state and onColumnVisibilityChange make visibility a controlled state. You can render a checkbox per column that calls column.toggleVisibility(), letting users control which columns appear without changing the column definitions.

Grouping with the Grouped Row Model

Grouping groups rows by the value of a specific column. Enable it with getGroupedRowModel, then call column.getToggleGroupingHandler() on the header:

JSAktifkan grouping
const table = useReactTable({
  data,
  columns,
  state: { grouping },
  onGroupingChange: setGrouping,
  getCoreRowModel: getCoreRowModel(),
  getGroupedRowModel: getGroupedRowModel(),
  getExpandedRowModel: getExpandedRowModel(),
})

getGroupedRowModel() turns the data into group rows, and getExpandedRowModel() manages which groups are open. Groups can be opened and closed with row.getIsExpanded() and row.getToggleExpandedHandler().

Aggregation

Computing Values Inside Groups

When data is grouped, numeric columns often need aggregation. TanStack Table ships built-in aggregationFn functions like sum, min, max, and count:

JSAgregasi sum pada kolom
columnHelper.accessor("gaji", {
  header: "Gaji",
  aggregationFn: "sum",
  aggregatedCell: ({ getValue }) => `Total: ${getValue()}`,
})

aggregationFn: "sum" computes the sum of values within each group. aggregatedCell decides how the aggregate value is rendered — here as Total. In group rows this column shows the sum; in detail rows it shows the original value.

Row Selection and Expansion

Checkboxes for Selecting Rows

Row selection is enabled with enableRowSelection. Add a checkbox column using columnHelper.display:

JSKolom checkbox untuk seleksi
columnHelper.display({
  id: "pilih",
  header: ({ table }) => (
    <input
      type="checkbox"
      checked={table.getIsAllRowsSelected()}
      onChange={table.getToggleAllRowsSelectedHandler()}
    />
  ),
  cell: ({ row }) => (
    <input
      type="checkbox"
      checked={row.getIsSelected()}
      onChange={row.getToggleSelectedHandler()}
    />
  ),
})

columnHelper.display creates a column with no data — specifically for actions like checkboxes. row.getIsSelected() and row.getToggleSelectedHandler() manage each row's state; table.getIsAllRowsSelected() manages select-all.

Virtualized Tables

Tables with Hundreds of Thousands of Rows

For large data, combine TanStack Table with TanStack Virtual. The rendered rows are replaced with virtual items:

JSVirtualized table
const table = useReactTable({
  data,
  columns,
  getCoreRowModel: getCoreRowModel(),
})
 
const virtualizer = useVirtualizer({
  count: table.getRowModel().rows.length,
  getScrollElement: () => parentRef.current,
  estimateSize: () => 40,
})
 
const rows = table.getRowModel().rows
const virtualRows = virtualizer.getVirtualItems()

virtualizer.getVirtualItems() returns only the visible rows. When rendering, virtual rows are positioned absolutely with translateY, and the container's total height is set to virtualizer.getTotalSize(). The full virtualization details are covered in episode 11.

Custom Cell Rendering

Cells as Components

The cell in a column definition can be a function that returns any element. This lets tables support badges, buttons, links, even small charts:

JSCustom cell dengan badge
columnHelper.accessor("status", {
  header: "Status",
  cell: ({ getValue }) => {
    const status = getValue()
    return (
      <span className={status === "aktif" ? "badge-hijau" : "badge-merah"}>
        {status}
      </span>
    )
  },
})

cell: ({ getValue }) => ... receives context and returns a React element. Because rendering is entirely yours, table design is limited only by your imagination — not by the library's API.

Info

Combine a virtualized table with getRowCanExpand for expanding rows that contain nested tables or forms. Episode 23 uses this combination in a full application.

Conclusion

Episode 9 enriched your table: column visibility with controlled state, grouping with aggregation, row selection through checkboxes, virtualized tables for massive data, and custom cell rendering for free-form displays.

Key takeaways:

  • Column visibility is controlled through state and onColumnVisibilityChange.
  • Grouping needs getGroupedRowModel and getExpandedRowModel.
  • aggregationFn provides built-in sum, min, max, and count.
  • columnHelper.display creates action columns without data.
  • Virtualized tables combine the row model with TanStack Virtual.
  • Custom cells can return any React element.

In the next episode, episode 10, we'll discuss router advanced and data management — deferred data loading with Await, error boundaries and notFound, route-based mutations with router invalidation, and full-stack routing patterns with data loaders. Your router will learn to handle heavy data and errors!

Learn TanStack - Table Advanced Features | Learn TanStack