Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Technology handbook

TanStack Table

Headless row models, columns, sorting, filtering, grouping, selection, pinning and virtualization.

Topics
32
Sections
5

Table hooks & state

Row model functions

getCoreRowModel and its siblings are what enable sorting, filtering, grouping and pagination.

  • Each row model is opt-in, so a plain table pays for nothing it does not use.
  • They run in a fixed order: filter, sort, group, expand, then paginate.
  • A feature that silently does nothing is usually a missing row model.

Controlled table state

Lift sorting, filtering or pagination into your own state and pass it back in.

  • Lifting state lets a URL or a store own the current sort and page.
  • The table stops tracking what you control, so the value must come back in.
  • Partial control is allowed: lift only the slices the application cares about.

Manual server-side state

Turn on manualSorting, manualFiltering or manualPagination when the server does the work.

  • Manual mode tells the table the rows it received are already sorted or paged.
  • Without it the table sorts the current page again and the order looks wrong.
  • Supply the total row count yourself, since the table cannot infer it.

Header and cell renderers

A header or cell definition may be a value, a function or a component, and all three render the same way.

  • A definition may be a plain value, an element or a function of the context.
  • One render helper handles all three, so call sites need no branching.
  • The function form receives the row, so a cell can render an action for it.

Column helpers and typing

Define columns through the typed helper so accessors and cell values stay in step.

  • The helper infers the cell type from the accessor it is given.
  • A renamed data field breaks the column definition rather than rendering blank.
  • Sorting and filtering functions are typed against the same value.

Reading header groups and rows

Draw the table from getHeaderGroups and getRowModel rather than from your source array.

  • Header groups already account for nesting, pinning and visibility.
  • Rendering the source array directly bypasses every feature the table adds.
  • The row model is what reflects the current sort, filter and page.

Table state slices

Subscribe to one piece of table state instead of re-rendering on every table change.

  • Subscribing to one slice keeps a header from re-rendering on a filter change.
  • It matters once a table holds hundreds of cells.
  • Read the slice where it is used rather than threading it from the top.

Row identity across state

Give each row a stable id, or selection and expansion follow positions instead of rows.

  • A stable id keeps a selection attached to a record across a re-sort.
  • Index-based identity silently selects a different row when the order changes.
  • The same id drives expansion, pinning and optimistic updates.

Table fundamentals

useReactTable

Create a table instance from data, columns and the row models a view needs.

  • The instance is the single object every header, row and cell is drawn from.
  • It holds state, row models and the feature configuration together.
  • The instance is recreated per render but keeps its state across renders.

Column definitions

Describe an accessor, a header and a cell renderer for each column.

  • A column says where its value comes from and how it is displayed.
  • Definitions are data, so they can be generated from a schema.
  • Per-column options carry sorting, filtering and sizing behaviour.

Accessor and display columns

Separate columns that read a value from columns that render controls.

  • An accessor column has a value and can therefore be sorted and filtered.
  • A display column holds checkboxes or buttons and has no value at all.
  • Giving a display column an accessor produces a column that sorts on nothing.

Row models

Add only the models a table uses, since each one costs work on every change.

  • Every added model recomputes on each data or state change.
  • A table without pagination should not include the pagination model.
  • The cost shows up on large datasets long before it shows up on small ones.

flexRender

Render a header or cell definition that may be a value, an element or a function.

  • The helper resolves whichever of the three definition forms was used.
  • It passes the header or cell context through to a function definition.
  • Calling a definition directly breaks as soon as someone passes a component.

Stable data and columns

Memoize both so the instance does not discard its state each render.

  • A new array identity each render makes the table rebuild its row models.
  • Column definitions are static and belong outside the component or in a memo.
  • The symptom is a table that loses its sort or selection while typing.

Sorting & filtering

Sorting state

Track which columns sort, in what direction, and whether multiple sorts combine.

  • The state is a list, which is what makes multi-column sorting expressible.
  • Direction and null placement are part of the column, not of the click handler.
  • Toggling cycles ascending, descending and off unless that is configured away.

Custom sort functions

Order values the default comparator cannot, such as localized text or nulls.

  • Locale-aware text sorting needs a comparator, not the default ordering.
  • Decide explicitly where empty values belong rather than letting them scatter.
  • A comparator registered by name can be reused across columns.

Column filters

Filter one column at a time with a predicate the column owns.

  • Each column owns its predicate, so a date column can filter by range.
  • Filters combine, so two columns narrow the rows together.
  • The filter value is state, which means it can be restored from a URL.

Global filter

Search across columns with a single input and a shared matching rule.

  • One input matches across the columns that opt into it.
  • The matching rule is yours: substring, fuzzy or normalised.
  • Debounce the input, since every keystroke recomputes the row model.

Faceted values

Offer filter options drawn from the data actually present in the column.

  • Facets are built from the data present, so a filter never offers an empty option.
  • Counts beside each option tell the reader what a choice will cost.
  • Facets must be computed after other filters if they should narrow together.

Manual filtering and sorting

Hand the work to a server and tell the table not to recompute it.

  • The server does the work and the table just renders what came back.
  • State changes become query parameters rather than local recomputation.
  • Forgetting the manual flag makes the table re-sort the page it was given.

Grouping & aggregation

Grouping state

Collapse rows under a grouping column and expand them on demand.

  • Grouping by a column collapses its rows under one header row.
  • The grouped column is removed from the leaf rows that sit beneath it.
  • Grouping runs before pagination, which changes what a page contains.

Aggregation functions

Summarize a group with a sum, mean or custom reducer.

  • An aggregate is computed per group, not per visible page.
  • Sum, mean and count cover most cases; a reducer covers the rest.
  • Aggregating a formatted string instead of its number is the usual bug.

Expanding

Control which groups or sub-rows are open, including nested hierarchies.

  • Expansion state is keyed by row id, so it survives a re-sort.
  • The same mechanism serves group rows and nested sub-rows.
  • Expanding everything on a large table defeats the point of grouping.

Sub-rows

Render tree data by pointing the table at each row's children.

  • A tree is described by pointing each row at its children.
  • Depth is available per row, which is what indentation is drawn from.
  • Filtering a tree has to decide whether a matching child keeps its parent.

Aggregated cell rendering

Show a different cell for a group row than for a leaf row.

  • A group row usually shows a total where a leaf shows a value.
  • Placeholder cells appear where a grouped column has nothing to show.
  • Rendering the same cell for both makes a summary row read as a record.

Grouping with pagination

Understand which rows a page counts when groups are collapsed.

  • Pages count the rows the model produced, which may be group rows.
  • Expanding a group can therefore change how many pages exist.
  • Decide whether a page should hold whole groups before choosing the size.

Selection, layout & scale

Row selection

Track selected rows by a stable row id rather than by index.

  • Selection is a map of row id to boolean, not a list of indexes.
  • Select-all across pages is a different feature from select-all on this page.
  • Keeping selection through a filter needs a decision about hidden rows.

Column visibility

Let a reader hide columns and persist that choice with the view.

  • Hidden columns stay in the definitions and can be restored.
  • Persisting the choice is what makes a wide table usable on a second visit.
  • A hidden column still filters unless it is excluded deliberately.

Column ordering

Reorder columns without changing the underlying definitions.

  • Order is a list of column ids kept separately from the definitions.
  • Pinned columns sit outside that order at their own edge.
  • Drag handles are yours to build; the table only tracks the resulting order.

Column sizing and resizing

Size columns and handle a resize interaction in your own markup.

  • The table tracks widths; the markup decides how they are applied.
  • Resizing updates on every pointer move, so it needs to stay cheap.
  • A minimum width keeps a dragged column from collapsing to nothing.

Column and row pinning

Freeze columns or rows at an edge while the rest scrolls.

  • A pinned column is rendered in its own group at the left or right.
  • Sticky positioning in the markup is what actually freezes it on screen.
  • Pinned rows are excluded from the scrolling body, so counts shift.

Virtualized rows

Render only visible rows for large datasets while keeping the row model intact.

  • Only the visible window is rendered while the row model stays complete.
  • Sorting and filtering still see every row, because they run on the model.
  • Row height estimation is what keeps the scrollbar honest.

Sources

  • TanStack Table official documentation

Ask follow-up questions on any topic in your dashboard.

Start learning