Filtering
Build filters for a list from ChoiceFilter, FilterBuilder and the other filter blocks and components. Keep the results and every active filter visible, and make each filter easy to edit or clear. Start with two decisions: when a change applies, and whether filters can be grouped.
1. Decide when a change applies
| Timing | Use it when | Build it with | Example |
|---|---|---|---|
| Immediately | Each choice is complete, easy to undo and cheap to apply, such as picking one status. | ChoiceFilter | Team directory example |
| Per filter, on Apply | One condition needs several inputs or a review first, such as a range, a date span or several checked values. | MultiChoiceFilter, TextFilter, NumberComparisonFilter, NumberRangeFilter, DateRangeFilter | Invoice list example |
| Whole set, on one Apply | Several conditions are edited together and results should change only once, such as a grouped query. | FilterBuilder, with draft and applied state | Grouped conditions example |
Choose the timing by how the filter is used, not by its field type. Closing a filter never applies it. Cancel, Escape and clicking outside all discard the draft (the edits not yet applied).
Changing the operator applies at once, unless the new operator needs a value first. If a panel has its own Apply button, pass the panel’s draft to each filter. Don’t add a second Apply inside it.
2. Decide flat or grouped
With flat filters, every condition must match. An All group matches when every condition in it matches, and an Any group matches when at least one does. Use groups only when people need a query like “Active members who are in Design or have more than three projects”.
Build grouped queries with FilterBuilder. Keep the query as a draft until it’s applied, so results don’t change mid-edit.
Grouped conditions
Team members
Filter your team by status, team or activity.
Matching members
2 of 5 members| Name | Status | Team | Projects |
|---|---|---|---|
| Priya Shah | active | design | 2 |
| Maya Chen | active | engineering | 6 |
View applied filter data
{
"kind": "group",
"id": "root",
"conjunction": "all",
"children": [
{
"kind": "rule",
"id": "status-rule",
"field": "status",
"operator": "is",
"value": "active"
},
{
"kind": "group",
"id": "team-group",
"conjunction": "any",
"children": [
{
"kind": "rule",
"id": "team-rule",
"field": "team",
"operator": "is",
"value": "design"
},
{
"kind": "rule",
"id": "projects-rule",
"field": "projects",
"operator": "greaterThan",
"value": "3"
}
]
}
]
}To move from quick filters to a grouped query, convert each block’s value into one FilterBuilder rule. Each block’s example file exports its own conversion. FilterBuilder doesn’t re-check a block’s number limits.
3. Start from a minimal example
Each block page starts with a minimal example and the files to copy:
- ChoiceFilter: one value from a short list. Applies immediately.
- MultiChoiceFilter: several values. Applies with Apply.
- TextFilter: text. Applies with Apply.
- NumberComparisonFilter: one number against a threshold. Applies with Apply.
- NumberRangeFilter: a number between two ends. Applies with Apply.
- DateRangeFilter: a range of calendar days. Applies with Apply.
Lay several filters out with blocks/filtering/applied-filters.tsx. It wraps filters onto new lines as needed, and holds no filter state. If filters are edited in a separate panel, show the applied ones as removable chips:
Invoice filters
Choose conditions in Filters. The chips below keep the applied conditions visible after the menu closes. Click a chip to remove that condition.
Showing paid invoices from India.
4. Show the result states
Keep active filters visible while results load or fail. Show a different message for an empty list, no matches and a failed request. Retry keeps the filters.
Show the total count across all pages, and go back to page one when a filter changes. The result-state examples use native inputs, but the same states apply to the blocks.
Loading
Team members
Find people across your teams.
Loading members…
Empty collection
Team members
Find people across your teams.
0 members
No members yet
Invite people to your teams to see them here.
No matches
Team members
Find people across your teams.
0 members
No matching members
Try another name or clear the filters.
Failure and retry
Team members
Find people across your teams.
Members unavailable
Members could not be loaded. Your filters are kept.
Examples
Team directory: immediate updates
Choosing a status or team updates the table at once. The filters have no Apply button.
Team members
Find people across your teams.
6 of 6 members
| Name | Team | Status | Projects |
|---|---|---|---|
Priya Shah Design | Design | Active | 2 |
Alex Morgan Engineering | Engineering | Active | 6 |
Maya Chen Design | Design | Invited | 0 |
Sam Rivera Operations | Operations | Active | 4 |
Noor Ahmed Engineering | Engineering | Invited | 1 |
Leo Martin Design | Design | Active | 5 |
Invoice list: Apply per filter
Each filter opens a checklist with its own Apply button. The trigger shows the applied values. Escape or clicking outside discards the changes.
Invoices
Track payments and find invoices that need your attention.
6 of 6 invoices
| Customer | Invoice | Status | Issued | Amount |
|---|---|---|---|---|
Acme Studio India | INV-1048 | Paid | 24 Sep 2026 | ₹48,000 |
Northstar Labs United States | INV-1047 | Open | 23 Sep 2026 | ₹1,25,000 |
Forma Design United Kingdom | INV-1046 | Paid | 22 Sep 2026 | ₹72,000 |
Common Ground India | INV-1045 | Overdue | 18 Sep 2026 | ₹36,000 |
Acme Studio India | INV-1044 | Open | 16 Sep 2026 | ₹24,000 |
Fieldwork United States | INV-1043 | Paid | 15 Sep 2026 | ₹96,000 |
These examples use sample data. The filtering blocks are experimental, so test them with your own data before you ship.
What your app owns
Your app owns the fields, permissions, values, filtering logic, requests, pagination and URL state. Cancel outdated requests and ignore late responses in your data layer.
Where to go next
- Components: FilterChip for a removal-only summary, FilterCondition for independently editable parts, FilterBuilder for grouped conditions.
- The source lives in
packages/react/src/blocks/filteringandpackages/react/src/patterns/filtering.