---
product: "AG Grid"
title: "Rich Select Cell Editor - Customisation"
description: "The Rich Select Cell Editor supports cell renderers, value formatting, search and typing behaviour, multi-selection, and complex object values."
enterprise: true
framework: javascript
version: "36.2.0"
related:
    - title: "Async Values"
      url: "https://www.ag-grid.com/archive/36.2.0/javascript-data-grid/provided-cell-editors-rich-select-async/"
llms: "https://www.ag-grid.com/archive/36.2.0/llms.txt"
---

# Rich Select Cell Editor - Customisation

The Rich Select Cell Editor supports cell renderers, value formatting, search and typing behaviour, multi-selection, and complex object values.

## Cell Renderer

The cell renderer used within the editor can be customised as shown below:

#### Rich Select with Cell Renderer

```ts
import {
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  IRichCellEditorParams,
  ModuleRegistry,
  TextEditorModule,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { colors } from "./colors";
import { ColourCellRenderer } from "./colourCellRenderer";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
]);

const columnDefs: ColDef[] = [
  {
    headerName: "Rich Select Editor",
    field: "color",
    cellRenderer: ColourCellRenderer,
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: colors,
      cellRenderer: ColourCellRenderer,
      valueListMaxHeight: 220,
    } as IRichCellEditorParams,
  },
];

function getRandomNumber(min: number, max: number) {
  // min and max included
  return Math.floor(window.agRandom() * (max - min + 1) + min);
}

const data = Array.from(Array(20).keys()).map(() => {
  const color = colors[getRandomNumber(0, colors.length - 1)];
  return { color };
});

let gridApi: GridApi;

const gridOptions: GridOptions = {
  defaultColDef: {
    width: 200,
    editable: true,
  },
  columnDefs: columnDefs,
  rowData: data,
};

const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
```

[Live example: Rich Select with Cell Renderer](https://www.ag-grid.com/archive/36.2.0/examples/provided-cell-editors-rich-select-customisation/rich-select-cell-renderer/typescript/)

```js
columnDefs: [
    {
        cellEditor: 'agRichSelectCellEditor',
        cellRenderer: ColourCellRenderer,
        cellEditorParams: {
            values: ['AliceBlue', 'AntiqueWhite', 'Aqua', /* .... many colours */ ],
            cellRenderer: ColourCellRenderer,
            valueListMaxHeight: 220
        }
        // ...other props
    }
]
```

The interface for the Cell Component is as follows:

```ts
interface ICellEditorRendererComp {
    // Optional - props for rendering.
    init?(props: IRichCellEditorRendererParams): void;

    // Mandatory - Return the DOM element of the component, this is what the grid puts into the cell
    getGui(): HTMLElement;

    // Optional - Gets called once by grid after rendering is finished - if your renderer needs to do any cleanup,
    // do it here
    destroy?(): void;
}
```

The Component is provided `props` containing, amongst other things, the value to be rendered.

```ts
class MyCustomEditorRenderer {
    // ...
    init(props) {
        // create the cell
        this.eGui = document.createElement('div');
        this.eGui.innerHTML = props.value;
    }
    // ...
}
```

The provided `props` (interface IRichCellEditorRendererParams) are:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `cellRendererParams` | `any` |  |  |  |
| `value` | `TValue[] \| TValue \| null` |  |  |  |
| `valueFormatted` | `string` |  |  |  |
| `getValue` | `Function` |  |  |  |
| `setValue` | `Function` |  |  |  |
| `setTooltip` | `Function` |  |  |  |
| `api` | `GridApi` |  |  |  |
| `context` | `TContext` |  |  |  |

## Search Values

Different types of search are possible within the editor list as shown below:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `searchType` | `'match' \| 'matchAny' \| 'fuzzy'` |  |  |  |

#### Rich Select Editor

```ts
import {
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  IRichCellEditorParams,
  ModuleRegistry,
  TextEditorModule,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { colors } from "./colors";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
]);

const columnDefs: ColDef[] = [
  {
    headerName: "Fuzzy Search",
    field: "color",
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: colors,
    } as IRichCellEditorParams,
  },
  {
    headerName: "Match Search",
    field: "color",
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: colors,
      searchType: "match",
    } as IRichCellEditorParams,
  },
  {
    headerName: "Match Any Search",
    field: "color",
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: colors,
      searchType: "matchAny",
    } as IRichCellEditorParams,
  },
];

function getRandomNumber(min: number, max: number) {
  // min and max included
  return Math.floor(window.agRandom() * (max - min + 1) + min);
}

const data = Array.from(Array(20).keys()).map(() => {
  const color = colors[getRandomNumber(0, colors.length - 1)];
  return { color };
});

let gridApi: GridApi;

const gridOptions: GridOptions = {
  defaultColDef: {
    width: 200,
    editable: true,
  },
  columnDefs: columnDefs,
  rowData: data,
};

const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
```

[Live example: Rich Select Editor](https://www.ag-grid.com/archive/36.2.0/examples/provided-cell-editors-rich-select-customisation/rich-select-search-values/typescript/)

```js
columnDefs: [
    {
        cellEditor: 'agRichSelectCellEditor',
        cellEditorParams: {
            values: ['AliceBlue', 'AntiqueWhite', 'Aqua', /* .... many colours */ ],
            searchType: 'match',
        }
        // ...other props
    }
]
```

## Allow Typing

The editor input can be configured to allow text input, which is used to match different parts of the editor list items as shown below:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `allowTyping` | `boolean` |  |  |  |

#### Rich Select Editor

```ts
import {
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  IRichCellEditorParams,
  ModuleRegistry,
  TextEditorModule,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { colors } from "./colors";
import { ColourCellRenderer } from "./colourCellRenderer";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
]);

const columnDefs: ColDef[] = [
  {
    headerName: "Allow Typing (Match)",
    field: "color",
    cellRenderer: ColourCellRenderer,
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: colors,
      searchType: "match",
      allowTyping: true,
      filterList: true,
      highlightMatch: true,
      valueListMaxHeight: 220,
    } as IRichCellEditorParams,
  },
  {
    headerName: "Allow Typing (MatchAny)",
    field: "color",
    cellRenderer: ColourCellRenderer,
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: colors,
      searchType: "matchAny",
      allowTyping: true,
      filterList: true,
      highlightMatch: true,
      valueListMaxHeight: 220,
    } as IRichCellEditorParams,
  },
];

function getRandomNumber(min: number, max: number) {
  // min and max included
  return Math.floor(window.agRandom() * (max - min + 1) + min);
}

const data = Array.from(Array(20).keys()).map(() => {
  const color = colors[getRandomNumber(0, colors.length - 1)];
  return { color };
});

let gridApi: GridApi;

const gridOptions: GridOptions = {
  defaultColDef: {
    flex: 1,
    editable: true,
  },
  columnDefs: columnDefs,
  rowData: data,
};

const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
```

[Live example: Rich Select Editor](https://www.ag-grid.com/archive/36.2.0/examples/provided-cell-editors-rich-select-customisation/rich-select-allow-typing/typescript/)

```js
columnDefs: [
    {
        cellEditor: 'agRichSelectCellEditor',
        cellRenderer: ColourCellRenderer,
        cellEditorParams: {
            values: ['AliceBlue', 'AntiqueWhite', 'Aqua', /* .... many colours */ ],
            allowTyping: true,
            filterList: true,
            highlightMatch: true,
        }
        // ...other props
    }
]
```

## Format Values

Items in the editor list can be formatted as shown below:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `formatValue` | `Function` |  |  |  |

#### Rich Select Format Values

```ts
import {
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  IRichCellEditorParams,
  ModuleRegistry,
  TextEditorModule,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
]);

const languages = ["English", "Spanish", "French", "Portuguese", "(other)"];

function getRandomNumber(min: number, max: number) {
  // min and max included
  return Math.floor(window.agRandom() * (max - min + 1) + min);
}

const columnDefs: ColDef[] = [
  {
    headerName: "Rich Select Editor",
    field: "language",
    cellEditor: "agRichSelectCellEditor",
    cellEditorParams: {
      values: languages,
      formatValue: (values) => values.toUpperCase(),
    } as IRichCellEditorParams,
  },
];

let gridApi: GridApi;

const gridOptions: GridOptions = {
  defaultColDef: {
    width: 200,
    editable: true,
  },
  columnDefs: columnDefs,
  rowData: new Array(100)
    .fill(null)
    .map(() => ({ language: languages[getRandomNumber(0, 4)] })),
};

const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
```

[Live example: Rich Select Format Values](https://www.ag-grid.com/archive/36.2.0/examples/provided-cell-editors-rich-select-customisation/rich-select-format-values/typescript/)

```js
columnDefs: [
    {
        cellEditor: 'agRichSelectCellEditor',
        cellEditorParams: {
            values: ['English', 'Spanish', 'French', 'Portuguese', '(other)'],
            formatValue: value => value.toUpperCase()
        }
        // ...other props
    }
]
```

## Multi Selection

The editor can be configured to allow the selection of multiple values as shown below:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `multiSelect` | `boolean` |  |  |  |
| `suppressMultiSelectPillRenderer` | `boolean` |  |  |  |

#### Rich Select Editor

```ts
import {
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  IRichCellEditorParams,
  ModuleRegistry,
  TextEditorModule,
  ValueFormatterParams,
  ValueParserParams,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { colors } from "./colors";
import { ColourCellRenderer } from "./colourCellRenderer";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
]);

const valueFormatter = (params: ValueFormatterParams) => {
  const { value } = params;
  if (Array.isArray(value)) {
    return value.join(", ");
  }

  return value;
};

const valueParser = (params: ValueParserParams) => {
  const { newValue } = params;

  if (newValue == null || newValue === "") {
    return null;
  }

  if (Array.isArray(newValue)) {
    return newValue;
  }

  return params.newValue.split(",");
};

type MultiSelectExampleConfig = {
  allowTyping: boolean;
  suppressMultiSelectPillRenderer: boolean;
  useCustomCellRenderer: boolean;
};

const config: MultiSelectExampleConfig = {
  allowTyping: false,
  suppressMultiSelectPillRenderer: false,
  useCustomCellRenderer: false,
};

function getColumnDefs(exampleConfig: MultiSelectExampleConfig): ColDef[] {
  const {
    allowTyping,
    suppressMultiSelectPillRenderer,
    useCustomCellRenderer,
  } = exampleConfig;

  return [
    {
      headerName: "Colours",
      field: "colors",
      cellRenderer: useCustomCellRenderer ? ColourCellRenderer : undefined,
      cellEditor: "agRichSelectCellEditor",
      cellEditorParams: {
        values: colors,
        cellRenderer: useCustomCellRenderer ? ColourCellRenderer : undefined,
        allowTyping,
        suppressMultiSelectPillRenderer,
        multiSelect: true,
        searchType: "matchAny",
        filterList: true,
        highlightMatch: true,
        valueListMaxHeight: 220,
      } as IRichCellEditorParams,
    },
  ];
}

function getRandomNumber(min: number, max: number) {
  // min and max included
  return Math.floor(window.agRandom() * (max - min + 1) + min);
}

const data = Array.from(Array(20).keys()).map(() => {
  const numberOfOptions = getRandomNumber(1, 4);

  const selectedOptions: string[] = [];

  for (let i = 0; i < numberOfOptions; i++) {
    const color = colors[getRandomNumber(0, colors.length - 1)];
    if (selectedOptions.indexOf(color) === -1) {
      selectedOptions.push(color);
    }
  }

  selectedOptions.sort();

  return { colors: selectedOptions };
});

let gridApi: GridApi;

const gridOptions: GridOptions = {
  defaultColDef: {
    flex: 1,
    editable: true,
    valueFormatter: valueFormatter,
    valueParser: valueParser,
  },
  columnDefs: getColumnDefs(config),
  rowData: data,
};

function getCheckboxValue(id: string): boolean {
  return document.querySelector<HTMLInputElement>(id)?.checked ?? false;
}

function applyExampleConfig(): void {
  config.allowTyping = getCheckboxValue("#allow-typing");
  config.suppressMultiSelectPillRenderer = getCheckboxValue(
    "#suppress-multi-select-pill-renderer",
  );
  config.useCustomCellRenderer = getCheckboxValue("#custom-cell-renderer");

  if (gridApi) {
    const activeEdit = gridApi.getEditingCells()[0];
    if (activeEdit) {
      gridApi.stopEditing();
    }

    gridApi.setGridOption("columnDefs", getColumnDefs(config));

    if (activeEdit) {
      requestAnimationFrame(() => {
        gridApi.startEditingCell({
          rowIndex: activeEdit.rowIndex,
          rowPinned: activeEdit.rowPinned,
          colKey: "colors",
        });
      });
    }
  }
}

const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);

if (typeof window !== "undefined") {
  // Attach external event handlers to window so they can be called from index.html
  (<any>window).applyExampleConfig = applyExampleConfig;
}
```

[Live example: Rich Select Editor](https://www.ag-grid.com/archive/36.2.0/examples/provided-cell-editors-rich-select-customisation/rich-select-multi-select/typescript/)

```js
columnDefs: [
    {
        cellEditor: 'agRichSelectCellEditor',
        cellEditorParams: {
            values: ['AliceBlue', 'AntiqueWhite', 'Aqua', /* .... many colours */ ],
            multiSelect: true,
        }
        // ...other props
    }
]
```

## Complex Objects

When working with complex objects, a `formatValue` callback function is required to convert that complex object into a string that can be rendered by the Rich Select Editor. If the `Grid Column` being edited is not using complex values, or if the Rich Select Editor value object has a different format (different properties) than the object used by the `Grid Column`, a `parseValue` callback function is required to convert the editor format into the grid column's format.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `formatValue` | `Function` |  |  |  |
| `parseValue` | `Function` |  |  |  |

> **Note**
>
> When working with `Cell Renderers`, a `formatValue` callback should still be provided so it will be possible to use functionality that relies on string values such as `allowTyping`.

#### Rich Select Editor

```ts
import {
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  IRichCellEditorParams,
  ModuleRegistry,
  TextEditorModule,
  createGrid,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { colors } from "./colors";

if (process.env.NODE_ENV !== "production") {
  // Enable extended validations only for development
  enableDevValidations();
}

ModuleRegistry.registerModules([
  TextEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
]);

const columnDefs: ColDef[] = [
  {
    headerName: "Color (Column as String Type)",
    field: "color",
    width: 250,
    cellEditorParams: {
      formatValue: (v) => v.name,
      parseValue: (v) => v.name,
      values: colors,
      searchType: "matchAny",
      allowTyping: true,
      filterList: true,
      valueListMaxHeight: 220,
    } as IRichCellEditorParams,
  },
  {
    headerName: "Color (Column as Complex Object)",
    field: "detailedColor",
    width: 290,
    valueFormatter: (p) => `${p.value.name} (${p.value.code})`,
    valueParser: (p) => p.newValue,
    cellDataType: "object",
    cellEditorParams: {
      formatValue: (v) => v.name,
      values: colors,
      searchType: "matchAny",
      allowTyping: true,
      filterList: true,
      valueListMaxHeight: 220,
    } as IRichCellEditorParams,
  },
];

let gridApi: GridApi;

const gridOptions: GridOptions = {
  defaultColDef: {
    width: 200,
    editable: true,
    cellEditor: "agRichSelectCellEditor",
  },
  columnDefs: columnDefs,
  rowData: colors.map((v) => ({ color: v.name, detailedColor: v })),
};

const gridDiv = document.querySelector<HTMLElement>("#myGrid")!;
gridApi = createGrid(gridDiv, gridOptions);
```

[Live example: Rich Select Editor](https://www.ag-grid.com/archive/36.2.0/examples/provided-cell-editors-rich-select-customisation/rich-select-complex-objects/typescript/)

```js
const colors = [
  { name: "Pink", code: "#FFC0CB" },
  // ...other values
];

columnDefs: [
    {
        cellEditor: 'agRichSelectCellEditor',
        valueFormatter: (p) => `${p.value.name} (${p.value.code})`,
        valueParser: (p) => p.newValue,
        cellDataType: 'object',
        cellEditorParams: {
            values: colors,
            formatValue: (v) => v.name,
        }
        // ...other props
    }
]
```

## API

Properties available on the `IRichCellEditorParams&lt;TData = any, TValue = any, GValue = any&gt;` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `values` | `TValue[] \| RichCellEditorValuesCallback` |  |  |  |
| `valuesPage` | `RichCellEditorValuesPageCallback` |  |  |  |
| `valuesPageInitialStartRow` | `number \| RichCellEditorValuesPageStartRowCallback` |  |  |  |
| `valuesPageSize` | `number` |  |  |  |
| `valuesPageLoadThreshold` | `number` |  |  |  |
| `cellHeight` | `number` |  |  |  |
| `cellRenderer` | `any` |  |  |  |
| `cellRendererParams` | `any` |  |  |  |
| `allowTyping` | `boolean` |  |  |  |
| `filterList` | `boolean` |  |  |  |
| `filterListAsync` | `boolean` |  |  |  |
| `searchType` | `'match' \| 'matchAny' \| 'fuzzy'` |  |  |  |
| `highlightMatch` | `boolean` |  |  |  |
| `multiSelect` | `boolean` |  |  |  |
| `suppressDeselectAll` | `boolean` |  |  |  |
| `suppressMultiSelectPillRenderer` | `boolean` |  |  |  |
| `searchDebounceDelay` | `number` |  |  |  |
| `valuePlaceholder` | `string` |  |  |  |
| `valueListGap` | `number` |  |  |  |
| `valueListMaxHeight` | `number \| string` |  |  |  |
| `valueListMaxWidth` | `number \| string` |  |  |  |
| `formatValue` | `Function` |  |  |  |
| `parseValue` | `Function` |  |  |  |
