Docs
CodeRabbit
Cloudflare
Railway
Clerk
SerpAPI
Netlify
OpenRouter
AG Grid
WorkOS
Sentry
Prisma
Unkey
Electric
CodeRabbit
Cloudflare
Railway
Clerk
SerpAPI
Netlify
OpenRouter
AG Grid
WorkOS
Sentry
Prisma
Unkey
Electric
Table API Reference
Column API Reference
Row API Reference
Cell API Reference
Header API Reference
Features API Reference
Static Functions API Reference
Legacy API Reference
Feature Guides

Faceting (React) Guide

Examples

Want to skip to the implementation? Check out these React examples:

React Setup

tsx
import { useTable, tableFeatures, columnFacetingFeature, columnFilteringFeature, createFacetedRowModel, createFacetedUniqueValues, createFacetedMinMaxValues, createFilteredRowModel, filterFns } from '@tanstack/react-table'

const features = tableFeatures({ columnFacetingFeature, columnFilteringFeature })

const table = useTable({
  features,
  rowModels: {
    filteredRowModel: createFilteredRowModel(filterFns),
    facetedRowModel: createFacetedRowModel(),
    facetedUniqueValues: createFacetedUniqueValues(),
    facetedMinMaxValues: createFacetedMinMaxValues(),
  },
  columns,
  data,
})
import { useTable, tableFeatures, columnFacetingFeature, columnFilteringFeature, createFacetedRowModel, createFacetedUniqueValues, createFacetedMinMaxValues, createFilteredRowModel, filterFns } from '@tanstack/react-table'

const features = tableFeatures({ columnFacetingFeature, columnFilteringFeature })

const table = useTable({
  features,
  rowModels: {
    filteredRowModel: createFilteredRowModel(filterFns),
    facetedRowModel: createFacetedRowModel(),
    facetedUniqueValues: createFacetedUniqueValues(),
    facetedMinMaxValues: createFacetedMinMaxValues(),
  },
  columns,
  data,
})

Faceting (React) Guide

Faceting is a feature that generates lists of values from your table's data, either for a single column (column faceting) or across the entire table (global faceting). For example, a list of unique values can be used as search suggestions in an autocomplete filter component, or a tuple of minimum and maximum values from a column of numbers can drive a range slider filter component. The same row models power both the per-column and table-wide APIs.

Column Faceting Row Models

In order to use any of the column faceting features, add the columnFacetingFeature to your features and the appropriate faceted row models to rowModels. Faceting exists to power filter UIs, so in practice you will also register the columnFilteringFeature and a filteredRowModel. Without a filtered row model, the faceted row models fall back to the pre-filtered rows and the facet values will not react to other columns' filters.

ts
import {
  useTable,
  tableFeatures,
  columnFacetingFeature,
  columnFilteringFeature,
  createFacetedRowModel,
  createFacetedMinMaxValues,
  createFacetedUniqueValues,
  createFilteredRowModel,
  filterFns,
} from '@tanstack/react-table'

const features = tableFeatures({ columnFacetingFeature, columnFilteringFeature })

const table = useTable({
  features,
  rowModels: {
    filteredRowModel: createFilteredRowModel(filterFns), // facet values react to other columns' filters
    facetedRowModel: createFacetedRowModel(), // required for faceting (other faceted row models depend on this)
    facetedMinMaxValues: createFacetedMinMaxValues(), // if you need min/max values
    facetedUniqueValues: createFacetedUniqueValues(), // if you need a list of unique values
  },
  columns,
  data,
})
import {
  useTable,
  tableFeatures,
  columnFacetingFeature,
  columnFilteringFeature,
  createFacetedRowModel,
  createFacetedMinMaxValues,
  createFacetedUniqueValues,
  createFilteredRowModel,
  filterFns,
} from '@tanstack/react-table'

const features = tableFeatures({ columnFacetingFeature, columnFilteringFeature })

const table = useTable({
  features,
  rowModels: {
    filteredRowModel: createFilteredRowModel(filterFns), // facet values react to other columns' filters
    facetedRowModel: createFacetedRowModel(), // required for faceting (other faceted row models depend on this)
    facetedMinMaxValues: createFacetedMinMaxValues(), // if you need min/max values
    facetedUniqueValues: createFacetedUniqueValues(), // if you need a list of unique values
  },
  columns,
  data,
})

First, you must include the facetedRowModel. This row model will generate a list of values for a given column. If you need a list of unique values, include the facetedUniqueValues row model. If you need a tuple of minimum and maximum values, include the facetedMinMaxValues row model.

Use Faceted Row Models

Once you have included the appropriate row models in your table options, you will be able to use the faceting column instance APIs to access the lists of values generated by the faceted row models.

ts
// list of unique values for autocomplete filter
const autoCompleteSuggestions = 
 Array.from(column.getFacetedUniqueValues().keys())
  .sort()
  .slice(0, 5000);
// list of unique values for autocomplete filter
const autoCompleteSuggestions = 
 Array.from(column.getFacetedUniqueValues().keys())
  .sort()
  .slice(0, 5000);
ts
// tuple of min and max values for range filter
const [min, max] = column.getFacetedMinMaxValues() ?? [0, 1];
// tuple of min and max values for range filter
const [min, max] = column.getFacetedMinMaxValues() ?? [0, 1];

Global Faceting

The same columnFacetingFeature and faceted row models also power table-wide (global) faceting. Where column faceting derives values from a single column, global faceting derives values across all columns, which is useful for populating a global filter's autocomplete suggestions or a global range slider. If your table also uses global filtering, register the globalFilteringFeature so global facet values react to the active global filter.

Use the global faceting table instance APIs to read the values:

ts
const globalFacetedRows = table.getGlobalFacetedRowModel().flatRows
const globalFacetedRows = table.getGlobalFacetedRowModel().flatRows
ts
// list of unique values for autocomplete filter
const autoCompleteSuggestions =
 Array.from(table.getGlobalFacetedUniqueValues().keys())
  .sort()
  .slice(0, 5000);
// list of unique values for autocomplete filter
const autoCompleteSuggestions =
 Array.from(table.getGlobalFacetedUniqueValues().keys())
  .sort()
  .slice(0, 5000);
ts
// tuple of min and max values for range filter
const [min, max] = table.getGlobalFacetedMinMaxValues() ?? [0, 1];
// tuple of min and max values for range filter
const [min, max] = table.getGlobalFacetedMinMaxValues() ?? [0, 1];

Custom (Server-Side) Faceting

Instead of using the built-in client-side faceting features, you can implement your own faceting logic on the server-side and pass the faceted values to the client-side. Supply custom rowModels.facetedUniqueValues and rowModels.facetedMinMaxValues factories. Each factory receives the table and a column ID and returns a thunk that resolves the faceted values. The column instance APIs (column.getFacetedUniqueValues() and column.getFacetedMinMaxValues()) will then return your server-provided values.

ts
const facetingQuery = useQuery(
  //...
)

const table = useTable({
  features,
  rowModels: {
    facetedUniqueValues: (_table, columnId) => () => {
      const uniqueValueMap = new Map<string, number>()
      //... populate from facetingQuery data for this columnId
      return uniqueValueMap
    },
    facetedMinMaxValues: (_table, columnId) => () => {
      //... read from facetingQuery data for this columnId
      return [min, max]
    },
  },
  columns,
  data,
  //...
})
const facetingQuery = useQuery(
  //...
)

const table = useTable({
  features,
  rowModels: {
    facetedUniqueValues: (_table, columnId) => () => {
      const uniqueValueMap = new Map<string, number>()
      //... populate from facetingQuery data for this columnId
      return uniqueValueMap
    },
    facetedMinMaxValues: (_table, columnId) => () => {
      //... read from facetingQuery data for this columnId
      return [min, max]
    },
  },
  columns,
  data,
  //...
})

The same factories also serve global faceting. Global faceting requests values with the internal __global__ column ID, so you can branch on it inside the same facetedUniqueValues and facetedMinMaxValues factories to return table-wide facet values:

ts
facetedUniqueValues: (_table, columnId) => () => {
  if (columnId !== '__global__') return new Map() // per-column facets
  return new Map(globalFacets.uniqueValues) // global facets
},
facetedUniqueValues: (_table, columnId) => () => {
  if (columnId !== '__global__') return new Map() // per-column facets
  return new Map(globalFacets.uniqueValues) // global facets
},

Alternatively, you don't have to put any of your faceting logic through the TanStack Table APIs at all. Just fetch your lists and pass them to your filter components directly.