---
title: Search state
description: Register filters, sorting, and pagination on views and zones.
---

State definitions do not belong to a scope until a view or zone registers them.
Register an object of state atoms. Its keys are local names for the bindings.
Read all values with `ctx.parse(view)` or `ctx.parse(zone)`. Place controls with
`view.state.name` or `zone.state.name`.

## Filter, sort, and paginate records

The SDK parses state and describes controls. Your resolver must apply filters,
sorting, and pagination to the query. It must also calculate the total count.

<BacklitExample path="state/table" view="list" />

`defineFilters` creates a `FilterBar`. `definePaginator({ perPage, param? })`
uses `page` as its default parameter. `defineSorter({ columns, param? })` uses
`by` as its default parameter. Supply field builders in `columns`.

A missing, repeated, fractional, zero, or negative page parses to page `1`.
The page size comes from the definition. A sorter parses to an ordered array
of `{ column, direction }`. It drops unknown columns and repeated columns.
The first occurrence of a column takes precedence.

Place bindings with `setPaginator(binding, { total })` and `setSorter(binding)`
on tables, record lists, or record timelines. Item lists and item timelines
support pagination but do not expose a sorter. Pagination and sorting on one
block must use the same scope.

## URL format

The root keywords are `f` for filters, `p` for pagination, and `s` for sorting.
A zone adds its name below the keyword.

```text title="Example query strings"
f[status]=open&p[page]=2&s[by]=-createdAt,title
f[activity][status]=open&p[activity][page]=2
f[tags]=new&f[tags]=urgent
```

A minus sign selects descending sort. A comma separates sort columns in
priority order. Array values use repeated keys.

`parseSearchParams(query)` accepts a leading `?` and returns a search object.
`stringifySearchParams(search)` returns text without a leading `?`. Unknown
keys remain in the object. These functions encode data; state atoms validate it.
Pass the parsed object as the final argument of `app.renderView` or
`app.renderZone`.

## Registration rules

State field names and zone names use letters, digits, underscores, and hyphens.
Two atoms with the same keyword in one scope cannot share a field name. Use
`param` to rename a paginator or sorter when a scope needs more than one.
A zone name cannot equal a view field name under the same keyword.

Filters and sorters have `definesResult: true`. A paginator has
`dependsOnResult: true`. The client uses these flags to clear an old page when
the result changes. State atoms sharing a keyword must use the same flags.

An extension can implement `StateAtomContract` with `KEYWORD`, `PARSE`,
`fieldNames`, `definesResult`, and `dependsOnResult`. Import symbols from
`@backlit/sdk/symbols` and the contract type from `@backlit/sdk/types`.
