Skip to content

Basics

Loading example…

enableColumnFooters renders a tfoot. Each column fills its cell either with an aggregate (the same aggregationFn grouping uses) or with whatever footer returns.

col.accessor('salary', { type: 'number', aggregationFn: 'sum' });
col.accessor('name', {
  footer: ({ table }) => table.getFilteredRowModel().rows.length + ' people',
});

Which rows count

footerAggregationScope is the whole question a total has to answer. 'filtered' sums everything the filters left, across pages, the number a reader usually means. 'page' sums what is on screen, which is what you want when the footer is a per-page subtotal.

Filter the demo above and watch the total move: the count follows the filters, not the page.

Staying visible

enableStickyFooter keeps the footer against the bottom of the scroll container, so the totals are readable without scrolling to the end of a long table. See Sticky header and footer.

Customization

A footer cell is a normal renderer, so it can hold anything: a formatted currency, a small bar, a link to a report. formatters keeps number and date formatting consistent between the body and the footer without repeating an Intl instance in every column.

Limitations

  • A footer aggregate needs a value. Display columns have none, so their footer is whatever footer returns or nothing at all.
  • Server mode aggregates what it received. The table cannot total rows it has never seen; return the totals from the API and render them with footer.
  • There is one footer row. Two levels of subtotal are grouping, not footers.

API

  • DataTableProps: enableColumnFooters, footerAggregationScope, enableStickyFooter, aggregationFns, formatters.
  • ColumnDef: footer, aggregationFn.
  • TableInstance: getFooterGroups, getFilteredRowModel, getPrePaginationRowModel.