Components
FilterBar
A row of filters above a table, list or chart: a search field, any filter controls you put in it, a button that clears every filter and the number of results. It wraps onto more lines when the row is narrow.
Preview
import { FilterBar, FilterBarSearch } from "@/components/ui/filter-bar"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
const clearFilters = () => { /* Reset every filter and the search text. */ }
<FilterBar label="Filter orders" activeCount={1} onClear={clearFilters} resultText="24 orders" className="w-full">
<FilterBarSearch label="Search orders" placeholder="Search orders" />
<Select defaultValue="paid">
<SelectTrigger aria-label="Status" className="w-36">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All statuses</SelectItem>
<SelectItem value="paid">Paid</SelectItem>
<SelectItem value="refunded">Refunded</SelectItem>
</SelectContent>
</Select>
</FilterBar>Usage
When to use
- Narrow a table, list or chart with a search field and a few filters in one row.
- Show how many results match and let someone clear every filter at once.
When not to use
- Search the whole app or run commands. Use Command.
- Fill in a form that is submitted. Use Field.
- Switch between views of the same content. Use Tabs.
Variants
size
Height of the search field and the clear button. Give every filter control in the bar the same size: sm above a dense table, md by default.
import { FilterBar, FilterBarSearch } from "@/components/ui/filter-bar"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
const clearFilters = () => { /* Reset every filter and the search text. */ }
<FilterBar size="sm" label="Filter orders" activeCount={1} onClear={clearFilters} resultText="24 orders" className="w-full">
<FilterBarSearch label="Search orders" placeholder="Search orders" />
<Select defaultValue="paid">
<SelectTrigger aria-label="Status" size="sm" className="w-36">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All statuses</SelectItem>
<SelectItem value="paid">Paid</SelectItem>
<SelectItem value="refunded">Refunded</SelectItem>
</SelectContent>
</Select>
</FilterBar>
<FilterBar label="Filter orders" activeCount={1} onClear={clearFilters} resultText="24 orders" className="w-full">
<FilterBarSearch label="Search orders" placeholder="Search orders" />
<Select defaultValue="paid">
<SelectTrigger aria-label="Status" className="w-36">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All statuses</SelectItem>
<SelectItem value="paid">Paid</SelectItem>
<SelectItem value="refunded">Refunded</SelectItem>
</SelectContent>
</Select>
</FilterBar>
<FilterBar size="lg" label="Filter orders" activeCount={1} onClear={clearFilters} resultText="24 orders" className="w-full">
<FilterBarSearch label="Search orders" placeholder="Search orders" />
<Select defaultValue="paid">
<SelectTrigger aria-label="Status" size="lg" className="w-36">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All statuses</SelectItem>
<SelectItem value="paid">Paid</SelectItem>
<SelectItem value="refunded">Refunded</SelectItem>
</SelectContent>
</Select>
</FilterBar>Examples
Orders
import { FilterBar, FilterBarSearch } from "@/components/ui/filter-bar"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
const clearFilters = () => { /* Reset every filter and the search text. */ }
<FilterBar label="Filter orders" activeCount={1} onClear={clearFilters} resultText="24 orders" className="w-full">
<FilterBarSearch label="Search orders" placeholder="Search orders" />
<Select defaultValue="paid">
<SelectTrigger aria-label="Status" className="w-36">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">All statuses</SelectItem>
<SelectItem value="paid">Paid</SelectItem>
<SelectItem value="refunded">Refunded</SelectItem>
</SelectContent>
</Select>
</FilterBar>Small, above a table
Every control takes the bar's size, sm above a dense table.
import { FilterBar, FilterBarSearch } from "@/components/ui/filter-bar"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
<FilterBar label="Filter members" size="sm" resultText="8 members" className="w-full">
<FilterBarSearch label="Search members" placeholder="Name or email" />
<ToggleGroup type="single" size="sm" variant="outline" defaultValue="all" aria-label="Role" className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-sm)))]">
<ToggleGroupItem value="all">All</ToggleGroupItem>
<ToggleGroupItem value="admin">Admins</ToggleGroupItem>
<ToggleGroupItem value="member">Members</ToggleGroupItem>
</ToggleGroup>
</FilterBar>Search only
import { FilterBar, FilterBarSearch } from "@/components/ui/filter-bar"
<FilterBar label="Filter projects" className="w-full">
<FilterBarSearch label="Search projects" placeholder="Search projects" />
</FilterBar>Do and don't
Do
- Put the search field first and the filters people use most right after it.
- Give every control in the bar the same size.
- Keep the results on screen while they update: mark the table pending instead of clearing it.
Don't
- Do not put actions that change data (Delete, Export) in the bar; put them in the table toolbar.
- Do not show the clear button when nothing is set.
- Do not hide the search field's name in the placeholder only.
Props
| Name | Type | Values | Default | Description |
|---|---|---|---|---|
| label required | string | - | - | On FilterBar: names the search landmark, such as Filter orders. On FilterBarSearch: names the search field, such as Search orders. |
| size | enum | sm | md | lg | md | Height of the search field and the clear button. Give every filter control in the bar the same size: sm above a dense table, md by default. |
| activeCount | number | - | 0 | How many filters are set. Above zero, and with onClear, the clear button shows. |
| onClear | () => void | - | - | Called by the clear button. Reset every filter and the search text. |
| clearLabel | string | - | Clear filters | Text of the clear button. Vietnamese: Xóa bộ lọc. |
| resultText | string | - | - | The number of results, such as 24 orders. Announced politely when it changes. |
Slots
| Name | Required | Description |
|---|---|---|
| filters | no | Children of FilterBar: FilterBarSearch and the filter controls, in reading order. |
Anatomy
| Part | Description |
|---|---|
| root | The search landmark: one row that wraps. |
| search | The search field. It grows to fill the row, up to 320px from sm up. |
| filters | Any filter controls between the search field and the clear button: Select, Combobox, DatePicker, ToggleGroup. |
| clear | The ghost button that clears every filter, shown while activeCount is above zero. |
| result | The number of results at the end of the row. |
Accessibility
Role: search
| Keys | Action |
|---|---|
| Tab | Moves through the search field, each filter control, then the clear button. |
| Escape | In the search field, clears the text (the browser's own search field behavior). |
- A search landmark named by label, such as EN `Filter orders`.
- The search field is named by its label, not by its placeholder, and has a decorative search icon.
- The result text is a polite status, so a screen reader hears EN `24 orders` after a filter changes.
- The clear button shows only while a filter is set; its text says what it does (EN `Clear filters`, VI `Xóa bộ lọc`).
Install
npx werewolf-ui add filter-barRun npx werewolf-ui init once in your app before adding components. Init sets up tokens, their CSS import and agent rules. Add installs this component and its dependencies while preserving your theme. See Installation for requirements and the alternative registry setup.