How should search and filters be designed in a SaaS app?
Search and filters in a SaaS app should work as one system: search narrows by text, filters narrow by attributes, and both show their current state at all times. The user should always be able to answer three questions at a glance: what am I looking at, why, and how do I get back to everything.
Most filter problems are state problems. People forget a filter is on, can't share what they see with a teammate, or lose their setup on refresh. That's why this guide spends as much time on URL sync and saved views as on the controls themselves. It's part of our larger guide to web app UI design.
What are the main filter UI patterns in filter UX design?
The main filter UI patterns are a filter bar, a side panel of facets, a query builder and a command-style filter input. Each fits a different amount of data and a different user.
Pattern | Best for | Trade-off |
|---|---|---|
Filter bar with dropdowns | Most SaaS lists with a handful of attributes | Gets crowded past a handful of filters |
Faceted side panel | Catalogs and large datasets with many attributes and counts | Costs horizontal space on dense tables |
"Add filter" builder | Power users combining many conditions (status is X and owner is Y) | Slower for simple, common filters |
Typed filter syntax | Keyboard-first tools and developers | Hard to discover without hints |
Our default for B2B products is a hybrid: a search box, the three or four most-used filters visible as dropdowns, and an "Add filter" button that opens the rest. That keeps the common case one click away without hiding advanced options. Keyboard-first products can also expose filters through the command menu, as covered in our guide to command palette design.
How does faceted search design work?
Faceted search design lets users narrow results by several independent attributes at once, such as status, owner, date and tag, with each facet showing its options. Facets combine with AND across attributes and usually with OR inside one attribute: status is Open or Pending, and owner is Dana.
- Show counts when they're cheap to compute. "Open (24)" helps users predict results and avoid dead ends.
- Hide or disable options with zero results, or show them dimmed so users understand why.
- Order options by usefulness, not alphabetically: most common first, with a search inside long lists like owners or tags.
- Make the logic visible when it isn't obvious. A short "any of" or "all of" label removes guesswork.
- Keep date filters human: presets like "Last 7 days" and "This quarter" first, a custom range second.
How should active filters be shown?
Active filters should appear as chips above the results, each with the filter name, value and a remove button, plus a "Clear all" link. This is one of the most important filter UX details, because hidden filters are a common cause of "where did my data go" support tickets.
Show the result count next to the chips ("18 of 240 tickets") so users can see how much they've narrowed. When a filter produces nothing, the empty result should echo the active filters and offer to clear them, using the no-results patterns from our guide to empty state design.
Should filters apply instantly or on confirm?
Filters should apply instantly when results return quickly, and on an explicit Apply button when queries are slow or expensive. Instant filtering feels better, but only if the list updates fast enough that the user doesn't stack several changes on top of a stale result.
Pros
- Instant: immediate feedback, fewer clicks, easier to explore
- Instant: works naturally with URL sync and the back button
- On confirm: avoids hammering slow queries while users pick several options
Cons
- Instant: layout shift and flicker if each change takes a second to load
- On confirm: users forget to press Apply and think filters are broken
- On confirm: harder to see the effect of each individual choice
If you apply instantly, debounce the search input, keep the previous results visible with a subtle loading indicator rather than blanking the table, and cancel stale requests. Our guide to loading state design covers how to avoid the flash of empty content.
Why should filters sync to the URL?
Filters should sync to the URL so that any filtered view can be shared, bookmarked, refreshed and navigated with the back button. It's a developer detail that design posts usually skip, and it changes how the product feels day to day.
Define the state shape
Agree on one list of parameters: search query, each filter, sort field, sort direction and page. Designers and engineers should name them together.
Write state to the URL
Every filter change updates the query string, for example ?status=open&owner=dana&sort=-updated. Use replace for typing in search and push for discrete filter changes, so the back button steps through meaningful views.
Read state from the URL
On load, the page reads the query string and renders that exact view. In Next.js this means the list reads search params, so a pasted link opens the same results.
Keep defaults out of the URL
Only write values that differ from the default, so clean links stay short and readable.
Validate what you read
Unknown or stale values (a deleted owner, a removed status) should be dropped gracefully with a note, not crash the page.
Implementation notes for React and Next.js teams
Treat the URL as the source of truth for filter state rather than mirroring local component state into it. That avoids the two drifting apart. Parse the query string once into a typed object, validate it with the same schema you use elsewhere, and derive the UI from that object.
For search inputs, keep the typed value locally for responsiveness and write it to the URL after a short debounce. Use history replace for those updates so every keystroke doesn't become a back-button entry.
If data is fetched on the server, the filtered URL can render the first page of results on the server, which also makes shared links load faster. Libraries exist that wrap this pattern for Next.js, but the principle is the same either way: one parsed, validated state object, read from and written to the URL.
What are saved views and when do you need them?
Saved views are named combinations of search, filters, sort and columns that users can return to in one click. You need them once a list becomes someone's daily workspace, like a support queue, a sales pipeline or a bug tracker. At that point filters stop being a search tool and become navigation.
- Personal vs shared views: let users keep private views and publish team views, with clear labels for which is which.
- Unsaved changes: when someone tweaks a saved view, show a "Save changes" or "Save as new view" prompt rather than silently overwriting it.
- Place views in the navigation: as tabs above the list or in the sidebar, so they're one click from anywhere.
- Views are URL state plus a name: if URL sync is in place, saved views are mostly a storage and naming feature on top.
Look at how the products in our roundup of SaaS UI design examples treat views as first-class navigation. Settings for default views often live alongside other preferences, a pattern covered in our guide to SaaS settings page design.
