# Faceting (Preact) Guide

## Examples

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

- [Faceted Filters](../examples/filters-faceted)

### Preact Setup

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

const features = tableFeatures({
  columnFacetingFeature,
  columnFilteringFeature,
  filteredRowModel: createFilteredRowModel(),
  facetedRowModel: createFacetedRowModel(),
  facetedUniqueValues: createFacetedUniqueValues(),
  facetedMinMaxValues: createFacetedMinMaxValues(),
  filterFns,
})

const table = useTable({
  features,
  columns,
  data,
})
```

## Faceting (Preact) 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` and the appropriate faceted row model factories to your `tableFeatures` call. 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/preact-table'

const features = tableFeatures({
  columnFacetingFeature,
  columnFilteringFeature,
  filteredRowModel: createFilteredRowModel(), // 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
  filterFns,
})

const table = useTable({
  features,
  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);
```

```ts
// 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
```

```ts
// 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];
```

### 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 `facetedUniqueValues` and `facetedMinMaxValues` factory slots on `tableFeatures`. 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 features = tableFeatures({
  columnFacetingFeature,
  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]
  },
})

const table = useTable({
  features,
  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
},
```

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.
