Global Filtering

A global filter is a single value, usually a search box, tested against every searchable column at once. A row survives when at least one of those columns matches. This page is the port of TanStack Table's Global Filtering guide; per-column filters are on Column Filtering.

The global filter and the column filters are applied by the same filteredRowModel stage of the pipeline, and a row has to pass both.

filteredRows : Table.State -> Table.RowModel Person
filteredRows state =
    Table.filteredRowModel config state (unfilteredRows state)

Global filter state

State.globalFilter is one Value, not a list, because there is only ever one global filter. Value.Null means "no global filter".

-- State.globalFilter : Value
-- Table.initialState.globalFilter == Value.Null

A search box writes Value.String. The slice is a Value rather than a String so a custom global filter function can take a range, a set of choices, or anything else Value can hold, which is what TanStack's any typing of this slice is for.

Config options

Option Type Default Description
enableGlobalFilter Bool True Global filtering for every column.
enableFilters Bool True Both column and global filtering. False switches off both.
globalFilterFn Maybe FilterFn Nothing The comparison the global filter uses. Nothing means the automatic choice. Set it with Table.withGlobalFilterFn.
getColumnCanGlobalFilter Maybe (Column row -> Bool) Nothing Decide per column whether the global filter searches it. Nothing uses the default rule below.
manualFiltering Bool False True makes Table.filteredRowModel return its input untouched.

Table.withGlobalFilterFn is the one builder here; the other fields are set with a record update on Table.config.

config : Table.Config Person
config =
    Table.config columns
        |> Table.withGetRowId (\person _ _ -> person.id)
        |> Table.withGlobalFilterFn FilterFn.includesString

A column is searched by the global filter when all of these hold: it has an accessor, Config.enableFilters and Config.enableGlobalFilter are on, the column has not opted out with withEnableGlobalFilter False, and Config.getColumnCanGlobalFilter agrees. The default rule, when that field is Nothing, keeps a column only if its first non-null value is a string or a number, which is TanStack's default.

namesOnlyConfig : Table.Config Person
namesOnlyConfig =
    let
        base : Table.Config Person
        base =
            Table.config columns
    in
    { base
        | getColumnCanGlobalFilter =
            Just
                (\column ->
                    List.member (Table.columnId column) [ "firstName", "lastName" ]
                )
    }

Global filter function

Config.globalFilterFn takes the same Table.FilterFn.FilterFn a column takes. The full list of built-ins, the four parts of a FilterFn, and how to write your own are on Column Filtering.

TanStack's guide lists the subset of its filter functions that make sense against a mixed set of columns, leaving out the ones that only suit a single typed column. The same subset applies here: includesString, includesStringSensitive, equalsString, equals, weakEquals, arrHas, arrIncludes, arrIncludesAll, arrIncludesSome, inNumberRange, between, and betweenInclusive all work against a mixed set of columns.

With no globalFilterFn set, the global filter uses globalAutoFilterFn, which is Table.FilterFn.includesString.

Column options

Builder Type Default Description
withEnableGlobalFilter Bool -> Column row -> Column row Nothing Whether the global filter searches this column. Nothing falls back to Config.enableGlobalFilter and Config.getColumnCanGlobalFilter.

There is no per-column global filter function: the global filter uses one comparison for every column it searches.

columns : List (Table.Column Person)
columns =
    [ Table.column "firstName" (.firstName >> Value.String)
        |> Table.withHeader "First name"
    , Table.column "lastName" (.lastName >> Value.String)
        |> Table.withHeader "Last name"
    , Table.column "department" (.department >> Value.String)
        |> Table.withHeader "Department"
    , Table.column "id" (.id >> Value.String)
        |> Table.withHeader "ID"
        |> Table.withEnableGlobalFilter False
    ]

Transitions

Function What it does
setGlobalFilter Set the global filter value.
resetGlobalFilter Clear it, back to Value.Null.
update : Msg -> Table.State -> Table.State
update msg state =
    case msg of
        SearchTyped typed ->
            Table.setGlobalFilter (Value.String typed) state

        SearchCleared ->
            Table.resetGlobalFilter state

Neither takes a RowModel. Unlike setColumnFilter, the global filter value is stored as written: there is no autoRemove step, so an empty search string is kept in state and simply matches everything.

Queries

Function Use it for
getCanGlobalFilter Listing or debugging which columns the search box actually searches.
getGlobalFilterFn Showing which comparison the search uses. Always returns a FilterFn.
globalAutoFilterFn The default, Table.FilterFn.includesString. It is a value, not a function.
globalFacetKey The column id "__global__", which the faceting functions take to mean "across every globally filterable column". See Faceting.

Read the current value straight off the state; there is no getter for it.

viewSearchInput : Table.State -> Html Msg
viewSearchInput state =
    input
        [ value (Value.toString state.globalFilter)
        , placeholder "Search"
        , onInput SearchTyped
        ]
        []

getCanGlobalFilter takes a RowModel because the default column rule samples the data for the column's value type. Pass the row model you handed to Table.filteredRowModel.

searchedColumnIds : Table.State -> List String
searchedColumnIds state =
    Table.leafColumns config
        |> List.map Table.columnId
        |> List.filter (Table.getCanGlobalFilter config (unfilteredRows state))

What this page does not cover

  • Controlled state, onGlobalFilterChange, and atoms. The State is always yours. See Table State.
  • initialState.globalFilter. Call setGlobalFilter on Table.initialState.
  • resetGlobalFilter(true). resetGlobalFilter always clears the value; there is no "back to the initial state" variant, because the package does not keep a copy of your starting state.
  • The filterFns registry. Config.globalFilterFn holds the function itself, not a registered name.
  • A global filter UI. As in TanStack, no input is rendered for you. Wire one up as shown above.

Example

Column Filters, ported from TanStack's Filters example, which includes a global search box.