---
metadata:
  - name: generator
    content: Diplodoc Platform v5.54.2
  - property: og:type
    content: article
  - property: article:section
    content: Plugin platform
  - property: og:title
    content: PluginFieldsSelect
  - property: article:tag
    content: Техническая инструкция
alternate:
  - https://yandex.ru/support/tracker/en/plugins/components/plugin-fields-select.md
  - https://yandex.ru/support/tracker/ru/plugins/components/plugin-fields-select.md
  - href: en/plugins/components/plugin-fields-select.md
    type: text/markdown
    title: Markdown version
  - href: ../../llms.txt
    type: text/markdown
    title: llms.txt
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.ru/support/tracker/en/llms.txt

[← Back to components list](https://yandex.ru/support/tracker/en/plugins/components/index.md)

# PluginFieldsSelect {#plugin-fields-select}

A dropdown for selecting Tracker fields within a plugin. Accepts a flat list of fields with category metadata and automatically groups them into collapsible sections. Supports search, multiple selection, apply/reset buttons, and a loading state.

## Basic usage {#usage}

```tsx
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField} from '@weavix/tracker-components';

const fields: PluginFieldsSelectField[] = [
    {id: 'summary', name: 'Summary', category: {id: '1', display: 'System fields'}},
    {id: 'description', name: 'Description', category: {id: '1', display: 'System fields'}},
    {id: 'sprint', name: 'Sprint', category: {id: '2', display: 'Custom fields'}},
];

<PluginFieldsSelect
    open={true}
    fields={fields}
    onOpenChange={(open) => console.log(open)}
    onItemSelect={(item) => console.log('selected', item)}
    onItemDeselect={(item) => console.log('deselected', item)}
/>;
```

## Example 1 — Initial global fields loading only {#example-1}

Loads all global fields once when mounted. Search works on the client side using the already loaded list.

```tsx
import React, {useEffect, useState} from 'react';
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField, TrackerSelectItem} from '@weavix/tracker-components';

interface Props {
    trackerApi: TrackerApi;
    onSubmit: (selected: TrackerSelectItem[]) => void;
}

export const GlobalFieldsSelect: React.FC<Props> = ({trackerApi, onSubmit}) => {
    const [fields, setFields] = useState<PluginFieldsSelectField[]>([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(false);
    const [selectedItems, setSelectedItems] = useState<TrackerSelectItem[]>([]);

    useEffect(() => {
        trackerApi.v3
            .get['/fields']()
            .then((result) => setFields(result.data))
            .finally(() => setLoading(false));
    }, [trackerApi]);

    return (
        <PluginFieldsSelect
            open={open}
            fields={fields}
            loading={loading}
            selectedItems={selectedItems}
            onOpenChange={setOpen}
            onItemSelect={(item) => setSelectedItems((prev) => [...prev, item])}
            onItemDeselect={(item) =>
                setSelectedItems((prev) => prev.filter((s) => s.id !== item.id))
            }
            onSubmit={() => onSubmit(selectedItems)}
            expandSystemGroup
        />
    );
};
```

## Example 2 — Global suggest on user input {#example-2}

Uses initial loading for the initial list and switches to the suggest endpoint when text is entered.

```tsx
import React, {useEffect, useState} from 'react';
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField, TrackerSelectItem} from '@weavix/tracker-components';

export const GlobalFieldsSelectWithSuggest: React.FC<Props> = ({trackerApi, onSubmit}) => {
    const [initialFields, setInitialFields] = useState<PluginFieldsSelectField[]>([]);
    const [fields, setFields] = useState<PluginFieldsSelectField[]>([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(false);
    const [selectedItems, setSelectedItems] = useState<TrackerSelectItem[]>([]);

    useEffect(() => {
        trackerApi.v3
            .get['/fields']()
            .then((result) => {
                setInitialFields(result.data);
                setFields(result.data);
            })
            .finally(() => setLoading(false));
    }, [trackerApi]);

    const handleSearchChange = async (text: string) => {
        // Suggest returns an empty response for empty input —
        // revert to the initial list when search is cleared
        if (!text) {
            setFields(initialFields);
            return;
        }
        const result = await trackerApi.v3.post['/fields/_suggest']({
            bodyParams: {input: text, readOnly: true, localFields: false, extended: true},
        });
        setFields(result.data);
    };

    return (
        <PluginFieldsSelect
            open={open}
            fields={fields}
            loading={loading}
            selectedItems={selectedItems}
            onOpenChange={setOpen}
            onSearchChange={handleSearchChange}
            onItemSelect={(item) => setSelectedItems((prev) => [...prev, item])}
            onItemDeselect={(item) =>
                setSelectedItems((prev) => prev.filter((s) => s.id !== item.id))
            }
            onSubmit={() => onSubmit(selectedItems)}
            expandGroupsOnSearch
        />
    );
};
```

## Example 3 — Global + local fields for specific queues {#example-3}

Extends Example 2 by adding queue-specific fields. If `queueKeys` is empty — only global suggest is used, since `localFields: true` with an empty `queues` array causes a request error.

```tsx
import React, {useEffect, useState} from 'react';
import {PluginFieldsSelect} from '@weavix/tracker-components';
import type {PluginFieldsSelectField, TrackerSelectItem} from '@weavix/tracker-components';

interface Props {
    trackerApi: TrackerApi;
    /** You must pass at least one queue key when using local fields */
    queueKeys: string[];
    onSubmit: (selected: TrackerSelectItem[]) => void;
}

export const LocalFieldsSelectWithSuggest: React.FC<Props> = ({
    trackerApi,
    queueKeys,
    onSubmit,
}) => {
    const [initialFields, setInitialFields] = useState<PluginFieldsSelectField[]>([]);
    const [fields, setFields] = useState<PluginFieldsSelectField[]>([]);
    const [loading, setLoading] = useState(true);
    const [open, setOpen] = useState(false);
    const [selectedItems, setSelectedItems] = useState<TrackerSelectItem[]>([]);

    useEffect(() => {
        trackerApi.v3
            .get['/fields']()
            .then((result) => {
                setInitialFields(result.data);
                setFields(result.data);
            })
            .finally(() => setLoading(false));
    }, [trackerApi]);

    const handleSearchChange = async (text: string) => {
        if (!text) {
            setFields(initialFields);
            return;
        }
        const hasQueues = queueKeys.length > 0;
        const result = await trackerApi.v3.post['/fields/_suggest']({
            bodyParams: {
                input: text,
                readOnly: true,
                localFields: hasQueues,
                extended: true,
                ...(hasQueues && {queues: queueKeys}),
            },
        });
        setFields(result.data);
    };

    return (
        <PluginFieldsSelect
            open={open}
            fields={fields}
            loading={loading}
            selectedItems={selectedItems}
            onOpenChange={setOpen}
            onSearchChange={handleSearchChange}
            onItemSelect={(item) => setSelectedItems((prev) => [...prev, item])}
            onItemDeselect={(item) =>
                setSelectedItems((prev) => prev.filter((s) => s.id !== item.id))
            }
            onSubmit={() => onSubmit(selectedItems)}
            expandGroupsOnSearch
        />
    );
};
```

## Main props {#props-table}

#|
|| **Prop** | **Type** | **Default** | **Description** ||
|| `fields` | `PluginFieldsSelectField[]` | — | Flat list of fields to display ||
|| `open` | `boolean` | — | Whether the dropdown is open ||
|| `onOpenChange`
|

```ts
(open: boolean) =>
  void
```

| — | Callback when the open state changes ||
|| `selectedItems` | `TrackerSelectItem[]` | — | Currently selected items ||
|| `loading` | `boolean` | `false` | Loading state — shows spinner ||
|| `onItemSelect`
|

```ts
(item: TrackerSelectItem) =>
  void
```

| — | Callback when an item is selected ||
|| `onItemDeselect`
|

```ts
(item: TrackerSelectItem) =>
  void
```

| — | Callback when an item is deselected ||
|| `onSubmit`
|

```ts
() => void
  | Promise<void>
```

| — | Callback when the apply button is clicked ||
|| `onReset`
|

```ts
() =>
  void
```

| — | Callback when the reset button is clicked ||
|| `onSearchChange`
|

```ts
(search: string) =>
  void
```

| — | Callback when search text changes ||
|| `showSearch` | `boolean` | `true` | Show search field ||
|| `showSubmit` | `boolean` | `true` | Show apply button ||
|| `showReset` | `boolean` | `false` | Show reset button ||
|| `submitButtonText` | `string` | — | Apply button text ||
|| `resetButtonText` | `string` | — | Reset button text ||
|| `expandGroupsOnSearch` | `boolean` | `false` | Expand groups when typing in the search field ||
|| `expandSystemGroup` | `boolean` | `false` | Expand the system fields group (id=`'1'`) by default ||
|| `singleSelect` | `boolean` | `false` | Single selection mode — closes the list after selection ||
|| `hideCheckbox` | `boolean` | `false` | Hide checkboxes next to items ||
|| `showMeta` | `boolean` | `false` | Show meta line under the item name ||
|| `disabledItemsIds` | `string[]` | — | IDs of items to display as unavailable ||
|| `footer` | `ReactNode` | — | Additional content below the item list ||
|| `className` | `string` | — | Additional CSS class for the root element ||
|#
