Filter Bar
Arrange search, filters and actions above a collection.
Filter Bar is the strip above a list or table that holds what narrows it: view tabs, a search field, filter menus and actions, with the applied filters underneath. It only arranges those controls; your application owns the query and the filters and filters the collection itself.
Installation
pnpm dlx shadcn@4.18.0 add @siteplane/filter-barComplete the one-time setup first. Registry JSON lists source files and dependencies.
For this page’s examples, also install:
pnpm dlx shadcn@4.18.0 add @siteplane/date-range-picker @siteplane/empty-state @siteplane/input-group @siteplane/menu @siteplane/resource-list @siteplane/tag-groupUsage
import {
FilterBar,
FilterBarControls,
FilterBarTabs,
} from "@/siteplane/components/filter-bar";
import { TabsTab } from "@/siteplane/components/tabs";
<FilterBar aria-label="Project filters">
<FilterBarControls>
<FilterBarTabs aria-label="Project view" defaultValue="mine">
<TabsTab value="mine">My projects</TabsTab>
<TabsTab value="starred">Starred</TabsTab>
</FilterBarTabs>
</FilterBarControls>
</FilterBar>;Or keep a search field in view and add actions:
import { Button } from "@/siteplane/components/button";
import {
FilterBar,
FilterBarActions,
FilterBarControls,
FilterBarSearch,
} from "@/siteplane/components/filter-bar";
import { Input } from "@/siteplane/components/input";
<FilterBar aria-label="Project filters">
<FilterBarControls>
<FilterBarSearch>
<Input aria-label="Search projects" type="search" />
</FilterBarSearch>
<FilterBarActions>
<Button>New project</Button>
</FilterBarActions>
</FilterBarControls>
</FilterBar>;Composition
FilterBar
├── FilterBarControls
│ ├── FilterBarTabs (view tabs with a search segment)
│ ├── FilterBarSearch
│ ├── FilterBarFilters
│ └── FilterBarActions
└── FilterBarActiveFiltersSearch in the tab bar
FilterBarTabs puts the search into the tab bar, for a list with a few views where a permanent search field would take room; the example at the top of the page is this bar above a project list. A Search segment leads the bar. Choosing it moves the tab indicator to Search, fades the tabs out and opens a field in the same bar, with the focus in the field. Escape or the clear button empties the search and returns to the tabs, with the selected tab unchanged and the focus back on Search. When the search must stay in view, or the tabs would not fit beside it, place FilterBarSearch next to a TabsList instead. The bar takes the rest of its row. With a filter beside it, set grow={false}: the bar is then as wide as its tabs, its surface ends after the last tab, and the filters keep their place at the end of the row. The search opens in that width.
The tabs are ordinary TabsTab elements: value, defaultValue and onValueChange work as on Tabs, and a tab can be disabled or carry an icon. The search keeps its own state. Read query to filter the collection. searching tells you whether the field is open, for a list that treats an open search differently from the selected view. Both can be controlled with query and searching, or left to the bar with defaultQuery and defaultSearching; closing the search empties the query, so a hidden query never filters the list.
<FilterBarTabs
aria-label="Project view"
onQueryChange={setQuery}
onSearchingChange={setSearching}
onValueChange={setView}
query={query}
searching={searching}
value={view}
>
…
</FilterBarTabs>Set variant="pill" to round the bar and the tabs fully, and size to match other tabs on the page. Set searchLabel, clearLabel and inputProps (aria-label, placeholder) for another language or a more specific name. The field is a search input named after the segment unless inputProps gives another name.
Tab reaches Search and then the selected tab; arrow keys move between the tabs, and Enter or Space selects one. Enter or Space on Search opens the field and moves the focus into it. Escape closes the search from the field, the clear button or the Search segment. On a narrow screen Search stays in place while the tabs scroll, and the edge where more tabs wait fades, as in a Scroll Area with scrollFade. While the tabs overflow, the strip that scrolls them takes a tab stop of its own, so keyboard users can scroll it with the arrow keys. Reduced motion makes the swap instant.
Filter menu and active filters
Put filter menus and a Clear button in FilterBarFilters, and list the applied filters in FilterBarActiveFilters. Removing a tag or choosing Clear updates the same application state, and the list below follows it.
Set open to whether any filter applies. When the last filter goes, the row collapses with a fade while it still shows its last tags, and the space above it closes with it, so the collection glides up instead of jumping. The row takes that space from the bar's --filter-bar-gap, 12 px or 8 px in the compact density; to change the spacing, set [--filter-bar-gap:…] on the FilterBar rather than a gap utility.
Date range
Place a date range picker next to the search when results are filtered by time. The range is application state like the query: the example keeps the invoices whose date falls inside it.
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
Filter | compact | default | provider / default | Spacing density. |
Filter | boolean | true | Shows the row of applied filters. false collapses it, and the space above it, with a fade. |
Filter | unknown | Base UI default | Controlled or initial tab, as on Tabs. |
Filter | (value, eventDetails) => void | unset | Selection change, as on Tabs. |
Filter | string | empty | Controlled or initial search text. |
Filter | (query: string) => void | unset | Called as the text is typed, and with an empty text when the search closes. |
Filter | boolean | false | Controlled or initial open state of the search field. |
Filter | (searching: boolean) => void | unset | Called when the search opens or closes. |
Filter | boolean | true | The bar takes the rest of its row. false gives it the width of its tabs, so its surface ends after the last tab; the search opens in that width. |
Filter | string | Search | Visible name of the leading segment and default name of the field. |
Filter | string | Clear search | Accessible name of the clear button. |
Filter | FilterBarTabsInputProps | unset | Props of the search input, such as aria-label or placeholder. |
Filter | default | pill | default | Rail and tab treatment, as on TabsList. |
Filter | sm | md | lg | xl | provider / lg | Shared size, as on Tabs. |
Filter | string | unset | Names the tab list. |
FilterBarProps extends native section props with density. FilterBarControls,
FilterBarSearch, FilterBarFilters, FilterBarActiveFilters and FilterBarActions
accept native div props, children, refs and string className;
FilterBarActiveFilters adds open. These parts arrange controls; none owns a
query, filter schema, fetching, selected filters or clear callback.
FilterBarTabsProps extends TabsProps without children and orientation; its
remaining props, className and refs reach the Tabs root, and its children are
TabsTab elements. Use public controls within the named layout parts.
Usage notes
Keep the collection’s pending, failure and empty states outside the bar and associated with results. Do not reset a focused search input when filtering; announce useful result changes without flooding a live region.
The tabs of FilterBarTabs have no panels: the collection below the bar is their content, so name the tab list for what it switches, such as the project view. While the search is open the tabs are hidden from assistive technology and cannot be focused; the selected tab is restored when it closes.