Filter Bar
Admin filter bar compound — search input, filter controls slot, removable active-filter chips, results count, and a clear-all affordance above a data-table. Built with CSS Modules and container queries — copy it into your project and own it completely.
Basic
With a Select Filter
With Active Filter Chips
Dense
Installation
npx visor add filter-barThis copies two files into your project:
components/ui/filter-bar/filter-bar.tsx— the componentcomponents/ui/filter-bar/filter-bar.module.css— the styles
The registry also pulls in search-input, badge, and button as dependencies.
Usage
import { useState } from 'react';
import { FilterBar } from '@/components/ui/filter-bar/filter-bar';
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from '@/components/ui/select/select';
export default function Example() {
const [search, setSearch] = useState('');
const [role, setRole] = useState<string | null>(null);
const activeFilters = role
? [{ id: 'role', label: `Role: ${role}`, onRemove: () => setRole(null) }]
: [];
return (
<FilterBar
searchValue={search}
onSearchChange={setSearch}
searchPlaceholder="Search users"
activeFilters={activeFilters}
onClearAll={() => {
setSearch('');
setRole(null);
}}
resultsCount="42 results"
>
<Select value={role ?? ''} onValueChange={setRole}>
<SelectTrigger>
<SelectValue placeholder="Role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="Admin">Admin</SelectItem>
<SelectItem value="Editor">Editor</SelectItem>
<SelectItem value="Viewer">Viewer</SelectItem>
</SelectContent>
</Select>
</FilterBar>
);
}API Reference
FilterBarProps
| Prop | Type | Default | Description |
|---|---|---|---|
searchValue | string | — | Controlled value for the search input. |
onSearchChange | (value: string) => void | — | Handler for search input changes. When omitted, the search input is not rendered. |
searchPlaceholder | string | 'Search...' | Placeholder text for the search input. |
children | React.ReactNode | — | Filter control slot — typically Select or Combobox instances rendered horizontally after the search. |
activeFilters | FilterBarChip[] | — | Active filters rendered as removable Badge chips on a secondary row. Each chip has { id, label, onRemove }. |
onClearAll | () => void | — | Handler for the clear-all button. The button only renders when this is provided AND at least one filter is active or a search value is present. |
clearLabel | React.ReactNode | 'Clear all' | Label for the clear-all button. |
resultsCount | React.ReactNode | — | Meta text rendered on the far right, e.g. "42 results". Wrapped in aria-live="polite" so filter changes are announced. |
dense | boolean | false | Tighter padding for dense admin layouts. |
className | string | — | Additional CSS class names to merge onto the root element. |
...props | React.HTMLAttributes<HTMLDivElement> | — | All standard HTML attributes are forwarded to the root div. |
The component also accepts all standard HTML attributes for the root <div>.
FilterBarChip
interface FilterBarChip {
id: string;
label: React.ReactNode;
onRemove: () => void;
}Source Files
After running npx visor add filter-bar, you'll have:
filter-bar.tsx
A forwardRef client component that composes SearchInput, a children slot for filter controls, Badge variant="secondary" chips with labeled remove buttons, and a ghost Button for clear-all. The root is a <div role="search"> so assistive tech treats the bar as a search region, and the results count is wrapped in aria-live="polite" so filter changes are announced.
filter-bar.module.css
All values use CSS custom properties from @loworbitstudio/visor-core. The component uses container-type: inline-size with a @container query so the bar stacks vertically inside narrow containers without viewport media queries.
Customization
After copying the component, you own it completely. Common customizations:
- Add a leading icon slot next to the search for domain iconography.
- Replace chips with a dropdown "Active filters" menu when the list gets long.
- Add a "Save view" affordance next to clear-all for persisted filter sets.
- Swap
role="search"forrole="region"with anaria-labelledbywhen nesting inside a larger search landmark.
Empty State
Admin placeholder compound for lists, tables, search results, and dashboard regions with no data. Icon, heading, description, primary and secondary action slots. Built with CSS Modules and container queries — copy it into your project and own it completely.
Kbd
Tiny primitive for rendering keyboard shortcuts using the semantic <kbd> element. Supports a single key via children or a multi-key sequence via the keys prop with a customizable separator. Built with CSS Modules — copy it into your project and own it completely.