Patterns
Filter Bar
Search and filters above a table, with active-filter badges and a clear action.
Search and active filters
Installation
With the Siteplane registry alias configured, add the component and import the installed source from your app.
CLI
pnpm dlx shadcn@4.16.1 add @siteplane/filter-barImport
import {
FilterBar,
FilterBarActions,
FilterBarActiveFilters,
FilterBarControls,
FilterBarFilters,
FilterBarSearch,
} from "@/components/patterns/filter-bar";Need the machine-readable source metadata? View registry JSON.
Usage
FilterBar organizes search, filters, active filter badges and actions without owning product state.
import { useState } from "react";
import {
FilterBar,
FilterBarActions,
FilterBarActiveFilters,
FilterBarControls,
FilterBarFilters,
FilterBarSearch,
} from "@/components/patterns/filter-bar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Menu,
MenuCheckboxItem,
MenuPopup,
MenuTrigger,
} from "@/components/ui/menu";
import { SearchIcon, SlidersHorizontalIcon, XIcon } from "lucide-react";
const statusOptions = ["Active", "Trial"] as const;
export function Example() {
const [query, setQuery] = useState("");
const [activeStatuses, setActiveStatuses] = useState<Set<string>>(
() => new Set(["Active"]),
);
const hasActiveFilters = Boolean(query || activeStatuses.size);
function setStatus(status: string, checked: boolean) {
setActiveStatuses((current) => {
const next = new Set(current);
if (checked) {
next.add(status);
} else {
next.delete(status);
}
return next;
});
}
function clearFilters() {
setQuery("");
setActiveStatuses(new Set());
}
return (
<FilterBar className="w-full max-w-2xl">
<FilterBarControls>
<FilterBarSearch>
<div className="relative">
<SearchIcon className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
<Input
aria-label="Search customers"
className="pl-8"
onChange={(event) => setQuery(event.target.value)}
placeholder="Search customers"
type="search"
value={query}
/>
</div>
</FilterBarSearch>
<FilterBarFilters>
<Menu>
<MenuTrigger render={<Button type="button" variant="outline" />}>
<SlidersHorizontalIcon />
Status
</MenuTrigger>
<MenuPopup align="end">
{statusOptions.map((status) => (
<MenuCheckboxItem
checked={activeStatuses.has(status)}
key={status}
onCheckedChange={(checked) => setStatus(status, checked)}
>
{status}
</MenuCheckboxItem>
))}
</MenuPopup>
</Menu>
{hasActiveFilters ? (
<FilterBarActions>
<Button onClick={clearFilters} type="button" variant="ghost">
<XIcon />
Clear
</Button>
</FilterBarActions>
) : null}
</FilterBarFilters>
</FilterBarControls>
{hasActiveFilters ? (
<FilterBarActiveFilters>
{query ? <Badge variant="outline">Search: {query}</Badge> : null}
{Array.from(activeStatuses).map((status) => (
<Badge key={status} variant="secondary">{status}</Badge>
))}
</FilterBarActiveFilters>
) : null}
</FilterBar>
);
}Purpose
Filter Bar is a registry:block for list and table screens. It organizes search, filter controls, active-filter badges and clear actions without owning product state or query serialization.
API Reference
FilterBarprovides layout slots only; the consuming screen owns search state, filters and URL synchronization.- Use Input for search, Menu or an appropriate selection primitive for filters, Badge for active filters and Button for actions.
- Show clear actions only when search or filters are active, and keep active filter badges in their own row.
- Search controls need visible or screen-reader labels. Active filters must describe their state in text rather than color alone.
- Use
density="compact"for a denser bar. Without a local value, density inherits fromSiteplaneUIProvider.
Motion
- The bar itself does not animate. Menus, Selects and other floating controls retain their native floating-panel motion.
- Reduced motion is inherited from those primitives and the global motion provider.
Accessibility
- Give every search and filter control a label; a placeholder is supporting copy, not an accessible name.
- Describe active filters with readable text rather than color alone.
- Keep clear actions keyboard reachable and name whether they clear one filter or the complete filter state.
Implementation Guidance
- Keep product filtering logic outside the pattern.
- Use native Siteplane controls in every slot instead of raw form or menu elements.
- Prefer the density prop over local spacing overrides.
Registry
Source Contract
Registry item: filter-bar
Files
src/components/patterns/filter-bar.tsxto components/patterns/filter-bar.tsx
Registry dependencies: @siteplane/base, @siteplane/badge, @siteplane/button, @siteplane/input, @siteplane/menu