---
name: FilterToolbar Implementation
description: Design and implementation guidance for filtering and managing collections with FilterToolbar
---

# FilterToolbar Implementation Guidance

FilterToolbar provides filtering, search, and actions for collections (lists, tables, grids).

## Choose Your Variant

```
Need 4+ filters? → vertical (sidebar/sheet)
Need toggle/pill displays? → vertical (sidebar/sheet)
Limited space? → compact
Simple 1-3 filters? → horizontal
```

### Variants

**Vertical** (Recommended for most cases)

- Use for: Sidebar filter panels, Dialog sheets, 4+ filters
- Placement: MUST be in sidebar or Dialog `variant="sheet"`
- Features: Collapsible sections, display variants (toggle/pills/checkbox)

**Compact** (Recommended for space-constrained UIs)

- Use for: Limited space, embedded toolbars, 4+ filters in tight layouts
- Shows: Single "Filters" button with count badge, popover for all filters

**Horizontal**

- Use for: ONLY 1-3 simple filters in main content
- Limitation: Gets cluttered with 4+ filters

## Basic Structure

**Component Order (Always):**

1. `FilterToolbarTitle` - Required, never omit
2. `FilterGroup` with `Filter` components
3. `FilterToolbarSearch` - Use for search (never raw input)
4. `FilterToolbarButtons` with `FilterToolbarButton` components

**Example:**

```tsx
<FilterToolbar variant="horizontal">
  <FilterToolbarTitle>Collection Name</FilterToolbarTitle>
  <FilterGroup>
    <Filter label="Status" options={statusOptions} />
    <Filter label="Category" options={categoryOptions} />
  </FilterGroup>
  <FilterToolbarSearch placeholder="Search items..." />
  <FilterToolbarButtons>
    <FilterToolbarButton leftIcon={Plus}>Add Item</FilterToolbarButton>
  </FilterToolbarButtons>
</FilterToolbar>
```

### Vertical Variant Example

```tsx
<FilterToolbar variant="vertical">
  <FilterToolbarTitle>Filter Results</FilterToolbarTitle>
  <FilterToolbarSearch placeholder="Search..." />
  <FilterGroup>
    <Filter label="Status" options={statusOptions} displayVariant="checkbox" />
    <Filter label="Priority" options={priorityOptions} displayVariant="pills" />
    <Filter label="Active" options={activeOptions} displayVariant="toggle" />
  </FilterGroup>
  <FilterToolbarButtons>
    <FilterToolbarButton>Clear All</FilterToolbarButton>
  </FilterToolbarButtons>
</FilterToolbar>
```

**Display options (vertical only):**

- `displayVariant="checkbox"` - 5+ options (compact, scannable)
- `displayVariant="toggle"` - Binary filters (Active/Inactive)
- `displayVariant="pills"` - 2-4 visual options (High/Medium/Low)

### Compact Variant Example

```tsx
<FilterToolbar variant="compact">
  <FilterToolbarTitle>Items</FilterToolbarTitle>
  <FilterGroup>
    <Filter label="Status" options={statusOptions} />
    <Filter label="Priority" options={priorityOptions} />
  </FilterGroup>
  <FilterToolbarSearch placeholder="Search..." />
  <FilterToolbarButtons>
    <FilterToolbarButton leftIcon={Plus}>Add</FilterToolbarButton>
  </FilterToolbarButtons>
</FilterToolbar>
```

## Key Components

### Search

```tsx
<FilterToolbarSearch
  placeholder="Search by name or email..."
  onSearch={handleSearch} // Auto-debounced (300ms)
/>
```

### Standard Filter

```tsx
const statusOptions = [
  { value: "all", label: "All Statuses" },
  { value: "active", label: "Active" },
  { value: "inactive", label: "Inactive" },
];

<Filter
  label="Status"
  options={statusOptions}
  value={selectedStatus}
  onChange={setSelectedStatus}
/>;
```

### Date Range Filter

```tsx
import { FilterDateRange, type DateRange } from "@/components/filter-toolbar";

const [dateRange, setDateRange] = useState<DateRange | undefined>();

<FilterDateRange
  label="Created Date"
  value={dateRange}
  onChange={setDateRange}
/>;
```

## Complete Example

```tsx
function CustomerList() {
  const [searchQuery, setSearchQuery] = useState("");
  const [statusFilter, setStatusFilter] = useState("all");

  const filteredCustomers = customers
    .filter((c) => statusFilter === "all" || c.status === statusFilter)
    .filter((c) => c.name.toLowerCase().includes(searchQuery.toLowerCase()));

  return (
    <>
      <FilterToolbar>
        <FilterToolbarTitle>
          Customers ({filteredCustomers.length})
        </FilterToolbarTitle>
        <FilterGroup>
          <Filter
            label="Status"
            options={statusOptions}
            value={statusFilter}
            onChange={setStatusFilter}
          />
        </FilterGroup>
        <FilterToolbarSearch
          onSearch={setSearchQuery}
          placeholder="Search customers..."
        />
        <FilterToolbarButtons>
          <FilterToolbarButton leftIcon={Plus}>
            Add Customer
          </FilterToolbarButton>
        </FilterToolbarButtons>
      </FilterToolbar>

      <DataTable data={filteredCustomers} columns={columns} />
    </>
  );
}
```

## Common Mistakes

- Don't use raw `<input>` or `Input` component for search - use `FilterToolbarSearch`
- Don't nest `<Button>` inside `FilterToolbarButton` - it's already a button
- Don't use `displayVariant="toggle"` or `displayVariant="pills"` in horizontal/compact variants
- Don't skip `FilterToolbarTitle` - always include it
- Don't put filters outside `FilterGroup`
- Don't forget "All" option in filter dropdowns
