# OperatorFilterPicker

**Category:** Features/Filter/Components

## Design

### Overview

The `OperatorFilterPicker` component provides a UI for users to select a filter operator and input a value. It renders a dropdown for operator selection and an input field for the filter value.

This component is designed to work with the `operatorFilter` factory.

**Important:** The `allowedOperators` array must include at least one operator that requires a value input (e.g., `EQUALS`, `STARTS_WITH`). If only value-less operators like `IS_EMPTY` or `NOT_EXISTS` are provided, the component will throw an error.

### Key Features

- **Operator selection**: Users can choose from a list of allowed operators via a dropdown.
- **Value input**: Text input for entering the filter value.
- **Automatic apply**: Filter is applied when user presses Enter or blurs the input.
- **Operators without values**: Supports operators like `IS_EMPTY` and `NOT_EXISTS` that don't require a value input.

### Supported Operators

| Operator | WQL | Description |
|----------|-----|-------------|
| `EQUALS` | `$eq` | Equal - exact match |
| `NOT_EQUALS` | `$ne` | Not equal - exclude exact match |
| `IN` | `$in` | In - value is in the provided array |
| `NOT_IN` | `$nin` | Not in - value is not in the provided array |
| `STARTS_WITH` | `$startsWith` | Starts with - string starts with the provided value |
| `IS_EMPTY` | `$isEmpty` | Is empty - value is null or empty |
| `CONTAINS` | `$contains` | Contains - string contains the provided value |
| `NOT_CONTAINS` | `$notContains` | Not contains - string does not contain the provided value |
| `EXISTS` | `$exists` | Exists - field is not null/undefined |
| `NOT_EXISTS` | `$notExists` | Not exists - field is null/undefined |


```tsx
import { OperatorFilterPicker, operatorFilter, FilterOperator } from '@wix/patterns';
```

---

### Examples

### string filter

A complete example showing how to use `operatorFilter` with a Table component. Select an operator from the side panel to filter the data.

```tsx
import { Avatar, Box, Heading } from '@wix/design-system';
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import {
  operatorFilter,
  FilterOperator,
  OperatorFilterPicker,
  transformOperatorFilterToWQL,
  Table,
  useTableCollection,
} from '@wix/patterns';
import { useHttpClient, searchContacts } from '../../../.storybook/http-client';

interface Contact {
  id: string;
  name: string;
  level: string;
  createdDate: string | Date;
}

function operatorFilterWithTableExample() {
  const httpClient = useHttpClient(100);

  const [nameFilter] = React.useState(() =>
    operatorFilter({
      name: 'name',
      allowedOperators: [
        FilterOperator.EQUALS,
        FilterOperator.NOT_EQUALS,
        FilterOperator.STARTS_WITH,
        FilterOperator.CONTAINS,
        FilterOperator.NOT_CONTAINS,
        FilterOperator.IS_EMPTY,
        FilterOperator.EXISTS,
        FilterOperator.NOT_EXISTS,
        FilterOperator.IN,
        FilterOperator.NOT_IN,
      ],
    }),
  );

  const state = useTableCollection<Contact>({
    queryName: 'OperatorFilterExample',
    paginationMode: 'offset',
    filters: {
      name: nameFilter,
    },
    fetchData: async ({ limit, offset, search, filters }) => {
      const nameFilters = filters.name
        ? transformOperatorFilterToWQL('name', filters.name)
        : [];

      const searchFilter = search ? [{ name: { $startsWith: search } }] : [];

      const allFilters = [...searchFilter, ...nameFilters];
      const filter = allFilters.length ? { $and: allFilters } : undefined;

      const response = (await httpClient.request(
        searchContacts({
          search: {
            filter,
            cursorPaging: { limit, offset },
          },
        }),
      )) as { data: { contacts: Contact[]; pagingMetadata: { total: number } } };

      return {
        items: response?.data?.contacts || [],
        total: response?.data?.pagingMetadata?.total,
      };
    },
    itemKey: (item) => item.id,
    itemName: (item) => item.name,
    fetchErrorMessage: () => 'Error fetching contacts',
  });

  return (
    <Box direction="horizontal" gap="SP4" height="500px">
      <Box flexGrow={1}>
        <CollectionPage height="500px">
          <CollectionPage.Header title={{ text: 'Contacts' }} />
          <CollectionPage.Content>
            <Table
              state={state}
              columns={[
                {
                  id: 'avatar',
                  title: '',
                  width: '50px',
                  render: (contact) => <Avatar name={contact.name} />,
                },
                {
                  id: 'name',
                  title: 'Name',
                  width: '200px',
                  render: (contact) => contact.name || '(empty)',
                },
                {
                  id: 'level',
                  title: 'Level',
                  width: '150px',
                  render: (contact) => contact.level,
                },
                {
                  id: 'createdDate',
                  title: 'Created',
                  render: (contact) =>
                    contact.createdDate
                      ? new window.Date(contact.createdDate).toLocaleDateString()
                      : '',
                },
              ]}
            />
          </CollectionPage.Content>
        </CollectionPage>
      </Box>
      <Box width="350px" direction="vertical" gap="SP2">
        <Heading size="small">Filter by Name</Heading>
        <OperatorFilterPicker filter={nameFilter} />
      </Box>
    </Box>
  );
}

export default operatorFilterWithTableExample;
```

## API

### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `filter` | `Filter<OperatorFilterValue<T>>` | Yes | - | A filter state object such as [ArrayFilter](./?path=/story/features-filter-factories--arrayfilter) |
| `fieldType` | `"SHORT_TEXT" \| "LONG_TEXT" \| "NUMBER" \| "BOOLEAN" \| "DATE" \| "DATE_TIME" \| "DATETIME" \| "TIME" \| "URL" \| "EMAIL" \| "IMAGE" \| "MEDIA_GALLERY" \| "AUDIO" \| "DOCUMENT" \| "MULTI_DOCUMENT" \| "RICH_TEXT" \| "RICH_CONTENT" \| "REFERENCE" \| "MULTI_REFERENCE" \| "OBJECT" \| "ARRAY" \| "ADDRESS" \| "COLOR" \| "INTEGER" \| "DECIMAL" \| "CHECKBOX" \| "DROPDOWN" \| "FILES" \| "MULTI_SELECT"` | No | - | The field type string used to resolve a prefix icon for the filter. Cairo maps this to the appropriate icon internally. |
| `layout` | `"button"` | No | - | Padding settings. If this prop it omitted, padding will exist on the sides of the filter.<br> <br> Supported values: <br> - `"button"`: Removes padding from the sides of the filter. |
| `toolbarItemProps` | `{ label?: ReactNode; }` | No | - | Customizes the filter in the toolbar.<br> <br> Supported properties: <br> - `label`: [string] Prefix for the filter element. |
| `toolbarTagProps` | `{ label?: string; }` | No | - | Customizes the filter tag in the toolbar.<br> <br> Supported properties: <br> - `label`: [string] Overrides the default filter name when filtered tag is shown. |
| `initiallyOpen` | `boolean` | No | - | Indicates whether the filter should be visible by default in the filters panel |
| `accordionItemProps` | `(AccordionItemType & { label?: string; })` | No | - | Customizes the filter [accordion](https://www.docs.wixdesignsystem.com/?path=/story/components-lists--accordion).<br> <br> Supported properties: <br> - `label`: [string] Accordion item title. You can also use `AccordionProps['items'][number].title` for more flexibility. <br> - Extends [AccordionProps['items'[number]](https://www.docs.wixdesignsystem.com/?path=/story/components-lists--accordion). |
| `popoverProps` | `PopoverCommonProps` | No | - | @deprecated |
| `onAppliedFilterTagRemove` | `((item: OperatorFilterValue<T>) => unknown)` | No | - | Callback that's run when a filter is removed by a visitor from the sub-toolbar. @param item |
| `renderToolbarTag` | `((item: OperatorFilterValue<T>) => Partial<TagListTag>)` | No | - | Customizes how the tag list in the sub-toolbar is rendered. <br><br> Extends [`TagListProps['tags'][number]`](https://www.docs.wixdesignsystem.com/?path=/story/components-lists-table--taglist). |
| `sectionTitle` | `string` | No | - | Title for the section in the accordion. |

