# FilterPicker

A versatile selection component that combines a trigger button with a searchable dropdown. It provides a space-efficient interface for selecting one or multiple items from a filtered list, with support for sections, custom summaries, and various UI states. Built with React Aria's accessibility features and the Cube `tasty` style system.

## When to Use

- Creating filter interfaces where users need to select from predefined options
- Building advanced search and filtering systems with multiple criteria
- Implementing tag-based selection systems with multiple categories
- Designing compact selection interfaces where space is limited
- Providing searchable selection without taking up permanent screen space
- Building user preference panels with organized option groups

## Component

---

### Properties

- **`selectedKey`** `string` — The selected key in controlled mode
- **`defaultSelectedKey`** `string` — The default selected key in uncontrolled mode
- **`selectedKeys`** `string[] | 'all'` — The selected keys in controlled multiple mode. Use "all" to select all items or an array of keys.
- **`defaultSelectedKeys`** `string[] | 'all'` — The default selected keys in uncontrolled multiple mode. Use "all" to select all items or an array of keys.
- **`selectionMode`** `'single' | 'multiple'` (default: `single`) — Selection mode for the picker
- **`allowsCustomValue`** `boolean` (default: `false`) — Whether to allow entering custom values that are not present in the predefined options
- **`isClearable`** `boolean` (default: `false`) — Whether the filter picker is clearable using a clear button in the rightIcon slot
- **`isLoadingItems`** `boolean` (default: `false`) — Whether items are currently loading. Shows a loading spinner in the search input suffix inside the popover. Unlike `isLoading`, does not disable the trigger.
- **`disallowEmptySelection`** `boolean` (default: `false`) — Whether to disallow empty selection
- **`disabledKeys`** `Key[]` — Array of keys for disabled items
- **`items`** `Iterable<T>` — Array of items to render when using the render function pattern for large datasets with dynamic content
- **`placeholder`** `string` — Placeholder text when no selection is made
- **`icon`** `ReactNode` — Icon to show in the trigger button
- **`type`** `'outline' | 'outline-2' | 'clear' | 'primary'` (default: `outline`) — Button styling type
- **`theme`** `'default' | 'special'` (default: `default`) — Button theme
- **`size`** `'small' | 'medium' | 'large'` (default: `medium`) — Size of the picker component
- **`searchPlaceholder`** `string` — Placeholder text in the search input
- **`emptyLabel`** `ReactNode` (default: context-aware: `No items` or `No results found`) — Label shown when the list is empty. When provided, overrides both defaults for any empty state
- **`filter`** `((textValue: string, inputValue: string) => boolean) | false` — Custom filter function for determining if an option should be included in search results
- **`header`** `ReactNode` — Custom header content
- **`footer`** `ReactNode` — Custom footer content
- **`renderSummary`** `((args: { selectedLabels, selectedKeys, selectionMode }) => ReactNode) | false` — Custom renderer for the summary shown inside the trigger when there is a selection
- **`isCheckable`** `boolean` (default: `false`) — Whether to show checkboxes for multiple selection mode
- **`shouldFocusWrap`** `boolean` (default: `false`) — Whether keyboard navigation should wrap around
- **`showSelectAll`** `boolean` (default: `false`) — Whether to show the "Select All" option in multiple selection mode
- **`selectAllLabel`** `string` (default: `All`) — Label for the "Select All" option
- **`description`** `string` — Field description
- **`message`** `string` — Help or error message
- **`listBoxStyles`** `Styles` — Custom styles for the dropdown list container within the popover
- **`popoverStyles`** `Styles` — Custom styles for the popover dialog that contains the FilterListBox
- **`triggerStyles`** `Styles` — Custom styles for the trigger button element
- **`triggerTooltip`** `string | TooltipProps` — Tooltip for the trigger button (separate from field tooltip)
- **`triggerDescription`** `string` — Description for the trigger button (separate from field description)
- **`prefix`** `ReactNode` — Content to show before the trigger button text
- **`suffix`** `ReactNode` — Content to show after the trigger button text
- **`hotkeys`** `string` — Keyboard shortcut that triggers the picker when pressed
- **`htmlType`** `'button' | 'submit' | 'reset'` (default: `button`) — HTML button type
- **`headerStyles`** `Styles` — Custom styles for the header area when header prop is provided
- **`footerStyles`** `Styles` — Custom styles for the footer area when footer prop is provided
- **`shouldFlip`** `boolean` (default: `true`) — Whether to flip the popover placement when it overflows
- **`containerPadding`** `number` (default: `8`) — Minimum padding in pixels between the popover and viewport edges
- **`sortSelectedToTop`** `boolean` — Sort selected items to the top when the popover opens (only works with `items` prop, defaults to `true` when items are provided)
- **`searchValue`** `string` — Controlled search input value
- **`onSearchChange`** `(value: string) => void` — Callback when search input value changes
- **`onSelectionChange`** `(keys: Key | Key[] | 'all' | null) => void` — Callback when selection changes
- **`onEscape`** `() => void` — Callback when Escape key is pressed
- **`onOptionClick`** `(key: Key) => void` — Callback when an option is clicked (non-checkbox area)
- **`onClear`** `() => void` — Callback called when the clear button is pressed
- **`onOpenChange`** `(isOpen: boolean) => void` — Callback called when the popover open state changes
- **`isReorderable`** `boolean` (default: `false`) — Enable drag-and-drop item reordering in the dropdown list
- **`onReorder`** `(newOrder: string[]) => void` — Callback when items are reordered via drag-and-drop or keyboard (Alt+Arrow)

### Base Properties

Supports [Base properties](../../BaseProperties.md)

### Field Properties

Supports all [Field properties](../../FieldProperties.md)

### Styling Properties

#### styles

Customizes the main wrapper element of the FilterPicker component.

**Sub-elements:**
- None - styles apply directly to the wrapper

#### triggerStyles

Customizes the trigger button element.

**Sub-elements:**
- None - styles apply directly to the trigger button

#### listBoxStyles

Customizes the dropdown list container within the popover.

**Sub-elements:**
- Same as FilterListBox: `Label`, `Description`, `Content`, `Checkbox`, `CheckboxWrapper`

#### popoverStyles

Customizes the popover dialog that contains the FilterListBox.

**Sub-elements:**
- Same as Dialog component sub-elements

#### searchInputStyles

Customizes the search input field within the FilterListBox.

#### listStyles

Customizes the list container element within the FilterListBox.

#### optionStyles

Customizes individual option elements within the FilterListBox.

#### sectionStyles

Customizes section wrapper elements within the FilterListBox.

#### headingStyles

Customizes section heading elements within the FilterListBox.

#### headerStyles

Customizes the header area when header prop is provided.

#### footerStyles

Customizes the footer area when footer prop is provided.

### Style Properties

These properties allow direct style application without using the `styles` prop:

- **Base:** `display`, `font`, `preset`, `hide`, `whiteSpace`, `opacity`, `transition`
- **Position:** `gridArea`, `order`, `gridColumn`, `gridRow`, `placeSelf`, `alignSelf`, `justifySelf`, `zIndex`, `margin`, `inset`, `position`
- **Dimension:** `width`, `height`, `flexBasis`, `flexGrow`, `flexShrink`, `flex`
- **Block:** `border`, `radius`, `shadow`, `outline`
- **Color:** `color`, `fill`, `fade`, `image`

### Modifiers

The `mods` property accepts the following modifiers you can override:

- **`placeholder`** `boolean` — Applied when no selection is made
- **`selected`** `boolean` — Applied when items are selected

## Sub-components

### FilterPicker.Item

Individual items within the FilterPicker dropdown. Each item is rendered using [Item](../content/Item.md) and supports all Item properties for layout, icons, descriptions, and interactive features.

#### Item API

For detailed information about all available item properties, see [Item documentation](../content/Item.md). Key properties include:

- **`key`** `string \| number` — Unique identifier for the item (required)
- **`children`** `ReactNode` — The main content/label for the option
- **`icon`** `ReactNode` — Icon displayed before the content
- **`rightIcon`** `ReactNode` — Icon displayed after the content
- **`description`** `ReactNode` — Secondary text below the main content
- **`descriptionPlacement`** `'inline' \| 'block'` — How the description is positioned
- **`prefix`** `ReactNode` — Content before the main text
- **`suffix`** `ReactNode` — Content after the main text
- **`tooltip`** `string \| boolean \| object` — Tooltip configuration
- **`styles`** `Styles` — Custom styling for the item
- **`qa`** `string` — QA identifier for testing

#### Example with Rich Items

```jsx
<FilterPicker label="Team Filters" selectionMode="multiple">
  <FilterPicker.Item 
    key="active-users" 
    icon={<IconUsers />}
    description="Filter by active users"
    suffix="12 users"
  >
    Active Users
  </FilterPicker.Item>
  <FilterPicker.Item 
    key="recent-activity" 
    icon={<IconClock />}
    description="Recent activity in the last week"
    rightIcon={<IconBadge />}
  >
    Recent Activity
  </FilterPicker.Item>
</FilterPicker>
```

### FilterPicker.Section

Groups related items together with an optional heading.

- **`title`** `ReactNode` — Optional heading text for the section
- **`children`** `FilterPicker.Item[]` — Collection of FilterPicker.Item components

## Content Patterns

### Static Children Pattern

The most common pattern for FilterPicker is to provide static children using `FilterPicker.Item` and `FilterPicker.Section` components:

```jsx
<FilterPicker label="Select Options">
  <FilterPicker.Item key="apple">Apple</FilterPicker.Item>
  <FilterPicker.Item key="banana">Banana</FilterPicker.Item>
  <FilterPicker.Section title="Vegetables">
    <FilterPicker.Item key="carrot">Carrot</FilterPicker.Item>
  </FilterPicker.Section>
</FilterPicker>
```

### Dynamic Content Pattern

For large datasets or dynamic content, use the `items` prop with a render function. This pattern enables automatic virtualization for performance:

```jsx
<FilterPicker
  label="Large Dataset"
  items={largeDataArray}
>
  {(item) => (
    <FilterPicker.Item key={item.id} textValue={item.name}>
      {item.name}
    </FilterPicker.Item>
  )}
</FilterPicker>
```

### Dynamic Sections Pattern

For hierarchical data with sections, use the `items` prop with nested render functions. Each section contains a `children` array of items.

```jsx
const categories = [
  { name: 'Fruits', children: [
    { key: 'apple', label: 'Apple' },
    { key: 'banana', label: 'Banana' },
  ]},
  { name: 'Vegetables', children: [
    { key: 'carrot', label: 'Carrot' },
    { key: 'broccoli', label: 'Broccoli' },
  ]},
];

<FilterPicker
  label="Choose items"
  placeholder="Choose items..."
  searchPlaceholder="Search..."
  items={categories}
>
  {(category) => (
    <FilterPicker.Section key={category.name} title={category.name} items={category.children}>
      {(item) => (
        <FilterPicker.Item key={item.key} textValue={item.label}>
          {item.label}
        </FilterPicker.Item>
      )}
    </FilterPicker.Section>
  )}
</FilterPicker>
```

**Key Benefits:**
- **Virtualization**: Automatically enabled for large lists without sections
- **Performance**: Only renders visible items in the DOM
- **Dynamic Content**: Perfect for data fetched from APIs or changing datasets
- **Memory Efficient**: Handles thousands of items smoothly
- **Selected Items Sorting**: When using the `items` prop, selected items are automatically sorted to the top when the popover reopens (can be controlled with `sortSelectedToTop`)

**When to Use:**
- Lists with 50+ items
- Dynamic data from APIs
- Content that changes frequently
- When virtualization performance is needed

## Variants

### Selection Modes

- `single` - Allows selecting only one item at a time
- `multiple` - Allows selecting multiple items

### Button Types

- `outline` - Default outlined button style; `isSelected` adds brand-tinted fill
- `clear` - Transparent background button; `isSelected` adds brand-tinted fill
- `primary` - Primary brand color button

### Sizes

- `small` - Compact size for dense interfaces (28px height)
- `medium` - Standard size for general use (32px height, default)
- `large` - Emphasized size for important actions (40px height)

## Examples

### Basic Usage

```jsx
<FilterPicker 
  label="Select Options" 
  placeholder="Choose items..."
  searchPlaceholder="Search options..."
>
  <FilterPicker.Item key="apple">Apple</FilterPicker.Item>
  <FilterPicker.Item key="banana">Banana</FilterPicker.Item>
  <FilterPicker.Item key="cherry">Cherry</FilterPicker.Item>
</FilterPicker>
```

### Clearable Selection

```jsx
<FilterPicker
  label="Clearable Filter Picker"
  placeholder="Choose items..."
  selectionMode="single"
  isClearable={true}
  defaultSelectedKey="apple"
>
  <FilterPicker.Item key="apple">Apple</FilterPicker.Item>
  <FilterPicker.Item key="banana">Banana</FilterPicker.Item>
  <FilterPicker.Item key="cherry">Cherry</FilterPicker.Item>
</FilterPicker>
```

### Multiple Selection

```jsx
<FilterPicker
  label="Select Multiple Options"
  placeholder="Choose items..."
  selectionMode="multiple"
  searchPlaceholder="Search options..."
>
  <FilterPicker.Section title="Fruits">
    <FilterPicker.Item key="apple">Apple</FilterPicker.Item>
    <FilterPicker.Item key="banana">Banana</FilterPicker.Item>
  </FilterPicker.Section>
  <FilterPicker.Section title="Vegetables">
    <FilterPicker.Item key="carrot">Carrot</FilterPicker.Item>
    <FilterPicker.Item key="broccoli">Broccoli</FilterPicker.Item>
  </FilterPicker.Section>
</FilterPicker>
```

### With Checkboxes

```jsx
<FilterPicker
  label="Select with Checkboxes"
  selectionMode="multiple"
  isCheckable={true}
  searchPlaceholder="Search options..."
>
  <FilterPicker.Item key="option1">Option 1</FilterPicker.Item>
  <FilterPicker.Item key="option2">Option 2</FilterPicker.Item>
</FilterPicker>
```

### Multiple Selection with Select All

```jsx
<FilterPicker
  label="Select permissions"
  placeholder="Choose permissions"
  selectionMode="multiple"
  showSelectAll={true}
  selectAllLabel="All Permissions"
>
  <FilterPicker.Item key="read">Read</FilterPicker.Item>
  <FilterPicker.Item key="write">Write</FilterPicker.Item>
  <FilterPicker.Item key="execute">Execute</FilterPicker.Item>
</FilterPicker>
```

### Custom Summary

```jsx
<FilterPicker
  label="Custom Summary Display"
  selectionMode="multiple"
  renderSummary={({ selectedLabels, selectedKeys }) => {
    if (selectedKeys.length === 0) return null;
    if (selectedKeys.length === 1) return `${selectedLabels[0]} selected`;
    return `${selectedKeys.length} items selected`;
  }}
>
  <FilterPicker.Item key="item1">Item 1</FilterPicker.Item>
  <FilterPicker.Item key="item2">Item 2</FilterPicker.Item>
</FilterPicker>
```

### No Summary (Icon Only)

```jsx
<FilterPicker
  selectionMode="multiple"
  renderSummary={false}
  icon={<FilterIcon />}
  aria-label="Apply filters"
>
  <FilterPicker.Item key="filter1">Filter 1</FilterPicker.Item>
  <FilterPicker.Item key="filter2">Filter 2</FilterPicker.Item>
</FilterPicker>
```

### With Header and Footer

```jsx
<FilterPicker
  label="Programming Languages"
  selectionMode="multiple"
  header={
    <Space gap="1x" flow="row" placeItems="center">
      <Title level={6}>Languages</Title>
      <Badge type="purple">12</Badge>
    </Space>
  }
  footer={
    <Text color="#dark.50" preset="t4">
      Popular languages shown
    </Text>
  }
>
  <FilterPicker.Section title="Frontend">
    <FilterPicker.Item key="javascript">JavaScript</FilterPicker.Item>
    <FilterPicker.Item key="react">React</FilterPicker.Item>
  </FilterPicker.Section>
</FilterPicker>
```

### With Custom Values

```jsx
<FilterPicker
  label="Custom Values Allowed"
  placeholder="Type or select..."
  selectionMode="multiple"
  allowsCustomValue={true}
  searchPlaceholder="Search or add custom value..."
>
  <FilterPicker.Item key="existing1">Existing Option 1</FilterPicker.Item>
  <FilterPicker.Item key="existing2">Existing Option 2</FilterPicker.Item>
</FilterPicker>
```

### Loading Items

Use `isLoadingItems` to indicate that items are currently being fetched. Unlike `isLoading`, the trigger stays enabled so users can still open the popover and interact with items that have already loaded. A loading spinner appears in the search input suffix.

```jsx
<FilterPicker
  label="Loading Items"
  placeholder="Select a fruit..."
  isLoadingItems={true}
  selectionMode="multiple"
>
  <FilterPicker.Item key="apple">Apple</FilterPicker.Item>
  <FilterPicker.Item key="banana">Banana</FilterPicker.Item>
</FilterPicker>
```

### Complex Example

```jsx
<FilterPicker
  label="Advanced Filter System"
  selectionMode="multiple"
  isCheckable={true}
  renderSummary={({ selectedKeys, selectedLabels }) => {
    if (selectedKeys.length === 0) return null;
    if (selectedKeys.length <= 3) 
      return `${selectedKeys.length} filters: ${selectedLabels.join(', ')}`;
    return `${selectedKeys.length} filters applied`;
  }}
  header={
    <Space gap="1x" flow="row" placeItems="center">
      <FilterIcon />
      <Title level={6}>Filter Options</Title>
    </Space>
  }
>
  <FilterPicker.Section title="Date & Time">
    <FilterPicker.Item key="today">Created Today</FilterPicker.Item>
    <FilterPicker.Item key="week">Created This Week</FilterPicker.Item>
  </FilterPicker.Section>
  <FilterPicker.Section title="Status">
    <FilterPicker.Item key="active">Active Items</FilterPicker.Item>
    <FilterPicker.Item key="draft">Draft Items</FilterPicker.Item>
  </FilterPicker.Section>
</FilterPicker>
```

### Reorderable

Enable drag-and-drop reordering inside the dropdown with `isReorderable`. Items display a grip handle and can be dragged to new positions. Use `Alt+Arrow` keys to reorder via keyboard.

```jsx
const [keyOrder, setKeyOrder] = useState([
  'revenue', 'orders', 'customers', 'sessions',
  'page-views', 'bounce-rate', 'conversion', 'aov',
  'retention', 'churn', 'ltv', 'arpu',
]);

<FilterPicker
  isReorderable
  selectionMode="multiple"
  defaultSelectedKeys={['revenue', 'orders', 'customers']}
  label="Metrics"
  onReorder={(newOrder) => setKeyOrder(newOrder)}
>
  {keyOrder.map((key) => (
    <FilterPicker.Item key={key}>{key}</FilterPicker.Item>
  ))}
</FilterPicker>
```

## Accessibility

### Keyboard Navigation

- `Tab` - Moves focus to the trigger button
- `Space/Enter` - Opens the dropdown popover
- `Arrow Up/Down` - Opens the popover (when closed) or navigates through options (when open)
- `Escape` - Closes the popover or clears search
- `Home/End` - Navigate to first/last option
- `Alt+ArrowUp` / `Alt+ArrowDown` - Reorder the focused item (when `isReorderable`)

### Screen Reader Support

- Trigger button announces current selection state
- Popover opening/closing is announced
- Search functionality is properly communicated
- Selection changes are announced immediately
- Loading and validation states are communicated

### ARIA Properties

- `aria-label` - Provides accessible label for the trigger button
- `aria-expanded` - Indicates whether the popover is open
- `aria-haspopup` - Indicates the button controls a listbox
- `aria-describedby` - Associates help text and descriptions

## Best Practices

1. **Do**: Provide clear, descriptive labels for the trigger
   ```jsx
   <FilterPicker label="Filter by Category" placeholder="Choose categories...">
     <FilterPicker.Item key="electronics">Electronics</FilterPicker.Item>
   </FilterPicker>
   ```

2. **Don't**: Use overly long option texts that will be truncated
   ```jsx
   // ❌ Avoid very long option text
   <FilterPicker.Item key="long">
     This is an extremely long option text that will be truncated
   </FilterPicker.Item>
   ```

3. **Do**: Use sections for logical grouping of small to medium lists
   ```jsx
   <FilterPicker.Section title="Categories">
     <FilterPicker.Item key="tech">Technology</FilterPicker.Item>
   </FilterPicker.Section>
   ```

4. **Do**: Use dynamic content pattern for large datasets
   ```jsx
   // ✅ For large lists (50+ items)
   <FilterPicker items={largeDataset}>
     {(item) => <FilterPicker.Item key={item.id}>{item.name}</FilterPicker.Item>}
   </FilterPicker>
   ```

5. **Do**: Use `showSelectAll` for efficient multiple selection in compact interfaces
   ```jsx
   <FilterPicker 
     selectionMode="multiple" 
     showSelectAll 
     selectAllLabel="Select All Options"
     placeholder="Choose items..."
   >
     {/* many items */}
   </FilterPicker>
   ```

6. **Do**: Use `isClearable` when users need to quickly clear selections
   ```jsx
   <FilterPicker 
     isClearable 
     selectionMode="single"
     label="Choose option"
   >
     {/* items */}
   </FilterPicker>
   ```

7. **Do**: Use `triggerStyles` for custom styling needs beyond standard types
8. **Accessibility**: Always provide meaningful labels and placeholders
9. **Performance**: Use `textValue` prop for complex option content
10. **UX**: Consider using `isCheckable` for multiple selection clarity

## Integration with Forms

This component supports all [Field properties](../../FieldProperties.md) when used within a Form. The component automatically handles form validation, field states, and integrates with form submission.

```jsx
<Form onSubmit={handleSubmit}>
  <FilterPicker
    name="categories"
    label="Product Categories"
    isRequired
    selectionMode="multiple"
    placeholder="Select categories..."
    rules={[{ required: true }]}
  >
    <FilterPicker.Section title="Electronics">
      <FilterPicker.Item key="phones">Phones</FilterPicker.Item>
      <FilterPicker.Item key="laptops">Laptops</FilterPicker.Item>
    </FilterPicker.Section>
    <FilterPicker.Section title="Clothing">
      <FilterPicker.Item key="shirts">Shirts</FilterPicker.Item>
      <FilterPicker.Item key="pants">Pants</FilterPicker.Item>
    </FilterPicker.Section>
  </FilterPicker>
</Form>
```

## Advanced Features

### Custom Summary Rendering

FilterPicker supports custom summary functions for the trigger display:

```jsx
const renderSummary = ({ selectedLabels, selectedKeys, selectionMode }) => {
  if (selectionMode === 'single') {
    return selectedLabels[0] ? `Selected: ${selectedLabels[0]}` : null;
  }
  
  if (selectedKeys.length === 0) return null;
  if (selectedKeys.length === 1) return selectedLabels[0];
  if (selectedKeys.length <= 3) return selectedLabels.join(', ');
  return `${selectedKeys.length} items selected`;
};

<FilterPicker renderSummary={renderSummary}>
  {/* items */}
</FilterPicker>
```

### Custom Values

When `allowsCustomValue={true}`, users can add new options:

```jsx
<FilterPicker
  allowsCustomValue={true}
  selectionMode="multiple"
  searchPlaceholder="Search or add new..."
>
  <FilterPicker.Item key="existing">Existing Option</FilterPicker.Item>
</FilterPicker>
```

Custom values:
- Are automatically added when typed and selected
- Persist across popover sessions  
- Appear in the selection summary
- Can be removed like any other selection

### Selected Items Sorting

When using the `items` prop, FilterPicker automatically sorts selected items to the top when the popover reopens. This helps users quickly see and manage their selections.

```jsx
// ✅ Default behavior - sorting enabled with items prop
<FilterPicker
  items={fruits}
  selectionMode="multiple"
>
  {(item) => <FilterPicker.Item key={item.key}>{item.label}</FilterPicker.Item>}
</FilterPicker>

// Explicitly disable sorting
<FilterPicker
  items={fruits}
  sortSelectedToTop={false}
  selectionMode="multiple"
>
  {(item) => <FilterPicker.Item key={item.key}>{item.label}</FilterPicker.Item>}
</FilterPicker>

// ❌ Sorting not available with JSX children
<FilterPicker selectionMode="multiple">
  <FilterPicker.Item key="apple">Apple</FilterPicker.Item>
  <FilterPicker.Item key="banana">Banana</FilterPicker.Item>
</FilterPicker>
```

**Key behaviors:**
- Sorting only works when using the `items` prop
- Selected items move to the top when the popover reopens
- Within sections, selected items sort to the top of their section
- Sorting is cached during a session to maintain order while the popover is open
- Defaults to `true` for items prop, `false` for JSX children
- Can be explicitly controlled with the `sortSelectedToTop` prop

### Icon-Only Mode

For space-constrained interfaces:

```jsx
<FilterPicker
  renderSummary={false}
  icon={<FilterIcon />}
  aria-label="Apply filters"
  type="clear"
>
  {/* options */}
</FilterPicker>
```

### Clearable Selection

Add a clear button to quickly reset selection:

```jsx
<FilterPicker
  isClearable
  selectionMode="single"
  label="Choose option"
  onClear={() => console.log('Selection cleared')}
>
  {/* options */}
</FilterPicker>
```

The clear button:
- Appears in the `rightIcon` slot when there's a selection
- Only shows when `isClearable={true}` and a selection exists
- Closes the popover when clicked
- Calls the optional `onClear` callback
- Is hidden when the picker is disabled or read-only

### Server-Side / Dynamic Search

When items come from a backend API, use `filter={false}` with controlled search to let the server handle filtering. Items are replaced when the response arrives, and `isLoadingItems` shows a subtle spinner in the search input while the fetch is in flight.

```jsx
const [items, setItems] = useState(initialItems);
const [searchValue, setSearchValue] = useState('');
const [isLoadingItems, setIsLoadingItems] = useState(false);

const handleSearchChange = useCallback((value) => {
  setSearchValue(value);
  setIsLoadingItems(true);
  debouncedFetch(value)
    .then(setItems)
    .finally(() => setIsLoadingItems(false));
}, []);

<FilterPicker
  items={items}
  searchValue={searchValue}
  onSearchChange={handleSearchChange}
  filter={false}
  sortSelectedToTop={false}
  isLoadingItems={isLoadingItems}
  placeholder="Search items..."
  selectionMode="multiple"
  onOpenChange={(isOpen) => {
    if (!isOpen) {
      setSearchValue('');
      setItems(initialItems);
    }
  }}
>
  {(item) => (
    <FilterPicker.Item key={item.id} textValue={item.name}>
      {item.name}
    </FilterPicker.Item>
  )}
</FilterPicker>
```

**How it works:**
- **`filter={false}`** disables client-side filtering so items are shown exactly as the server returns them
- **`searchValue` + `onSearchChange`** give you control over the search input; debounce and fetch on your side
- **`items`** is a reactive prop — replace it with server results and the list updates automatically
- **`isLoadingItems`** shows a loading spinner in the search input suffix while fetching. While loading, stale items that do not text-match the current search are hidden client-side so the user only sees relevant suggestions
- **Selected custom values** (with `allowsCustomValue` in multi-select) are filtered against the search input too, so they don't appear when they don't match
- **`sortSelectedToTop={false}`** is recommended when the server controls item order
- **`emptyLabel`** can be used to customize the empty state message (e.g. `"Loading items..."` during initial load)
- **Reset on close** — use `onOpenChange` to restore the initial item set and clear the search when the popover closes, ensuring the trigger label resolves correctly

**Tips:**
- Debouncing is the consumer's responsibility (300-500ms is typical)
- During the debounce delay, old items remain visible — if you want instant client-side feedback while waiting, use a filter function instead of `false`

## Performance

### Optimization Tips

- **Use Dynamic Content Pattern**: For large datasets (50+ items), use the `items` prop with render function to enable automatic virtualization
- **Avoid Sections for Large Lists**: Virtualization is disabled when sections are present, so avoid sections for very large datasets
- **Use `textValue` prop**: For complex option content, provide searchable text that includes more context than just the visible label
- **Implement custom filter functions**: For specific search needs or performance-critical filtering
- **Consider debounced selection changes**: For real-time updates that trigger expensive operations
- **Use external filtering**: For server-side filtering or complex custom logic

### Virtualization

When using the dynamic content pattern (`items` prop) without sections, FilterPicker automatically enables virtualization:

```jsx
// ✅ Virtualization enabled - excellent performance with large datasets
<FilterPicker items={largeArray}>
  {(item) => <FilterPicker.Item key={item.id}>{item.name}</FilterPicker.Item>}
</FilterPicker>

// ❌ Virtualization disabled - sections prevent virtualization
<FilterPicker items={largeArray}>
  <FilterPicker.Section title="All Items">
    {(item) => <FilterPicker.Item key={item.id}>{item.name}</FilterPicker.Item>}
  </FilterPicker.Section>
</FilterPicker>
```

### Content Optimization

```jsx
// Optimized for performance
<FilterPicker.Item 
  key="complex" 
  textValue="John Doe - Senior Developer"
>
  <UserCard user={user} />
</FilterPicker.Item>
```

## Related Components

- [FilterListBox](./FilterListBox.md) - The underlying searchable list component
- [Select](./Select.md) - Use for simple selection without search functionality
- [ComboBox](./ComboBox.md) - Use when users need to enter custom values
- [ListBox](./ListBox.md) - Use for basic list selection without search
- [Button](../actions/Button.md) - The underlying trigger component
