---
product: "AG Grid"
title: "Edit Components"
description: "Cell Editors handle the edit operation in the React data grid. Use one of seven provided Cell Editors or create a custom cell editor component."
framework: react
version: "36.2.0"
related:
    - title: "Overview"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/cell-editing/"
    - title: "Start / Stop Editing"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/cell-editing-start-stop/"
    - title: "Parsing Values"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/value-parsers/"
    - title: "Saving Values"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/value-setters/"
    - title: "Provided Cell Editors"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/provided-cell-editors/"
    - title: "Undo / Redo Edits"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/undo-redo-edits/"
    - title: "Full Row"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/cell-editing-full-row/"
    - title: "Validation"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/cell-editing-validation/"
    - title: "Batch Editing"
      url: "https://www.ag-grid.com/archive/36.2.0/react-data-grid/cell-editing-batch/"
llms: "https://www.ag-grid.com/archive/36.2.0/llms.txt"
---

# Edit Components

A Cell Editor Component is the UI that appears, normally inside the Cell, that takes care of the Edit operation. You can select from the [Provided Cell Editors](https://www.ag-grid.com/archive/36.2.0/react-data-grid/provided-cell-editors/) or create your own Custom Cell Editor Components.

The example below shows some Provided Editor Components and some Custom Editor Components.

#### Simple Editor Components

```tsx
'use client';
import React, { StrictMode, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";

import type { ColDef } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  CustomEditorModule,
  NumberEditorModule,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import { getData } from "./data";
import GenderRenderer from "./genderRenderer";
import MoodEditor from "./moodEditor";
import MoodRenderer from "./moodRenderer";
import SimpleTextEditor from "./simpleTextEditor";
import "./styles.css";

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

const modules = [
  NumberEditorModule,
  TextEditorModule,
  CustomEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>(getData());
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "first_name", headerName: "Provided Text" },
    {
      field: "last_name",
      headerName: "Custom Text",
      cellEditor: SimpleTextEditor,
    },
    {
      field: "age",
      headerName: "Provided Number",
      cellEditor: "agNumberCellEditor",
    },
    {
      field: "gender",
      headerName: "Provided Rich Select",
      cellRenderer: GenderRenderer,
      cellEditor: "agRichSelectCellEditor",
      cellEditorParams: {
        cellRenderer: GenderRenderer,
        values: ["Male", "Female"],
      },
    },
    {
      field: "mood",
      headerName: "Custom Mood",
      cellRenderer: MoodRenderer,
      cellEditor: MoodEditor,
      cellEditorPopup: true,
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      editable: true,
      flex: 1,
      minWidth: 100,
    };
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Simple Editor Components](https://www.ag-grid.com/archive/36.2.0/examples/cell-editors/component-editor-2/reactFunctionalTs/)

The provided editors' input fields share the grid-wide input behaviour (clear button on supported inputs, browser autocomplete) described in [Input Fields](https://www.ag-grid.com/archive/36.2.0/react-data-grid/input-fields/).

## Custom Components

Custom Cell Editor Components are Controlled Components, which receive a value as part of the props, and pass value updates back to the grid via the `onValueChange` callback. The value is not set until editing stops.

The provided props follow the `CustomCellEditorProps` interface which is listed below under [API Reference](https://www.ag-grid.com/archive/36.2.0/react-data-grid/cell-editors/#customcelleditorprops).

```jsx
export default ({ value, onValueChange }) => {
    return (
        <input
            type="text"
            value={value || ''}
            onChange={({ target: { value }}) => onValueChange(value === '' ? null : value)}
        />
    );
}
```

> **Note**
>
> In previous versions of the grid, custom components were declared in an imperative way. See [Migrating to Use reactiveCustomComponents](https://www.ag-grid.com/archive/36.2.0/react-data-grid/upgrading-to-ag-grid-31-1/#migrating-custom-components-to-use-reactivecustomcomponents-option) for details on how to migrate to the current format.

The following callbacks can be passed to the `useGridCellEditor` hook (`CustomCellEditorCallbacks` interface). All the callbacks are optional. The hook only needs to be used if callbacks are provided.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `isCancelBeforeStart` | `Function` |  |  |  |
| `isCancelAfterEnd` | `Function` |  |  |  |
| `focusIn` | `Function` |  |  |  |
| `focusOut` | `Function` |  |  |  |
| `getValidationElement` | `Function` |  |  |  |
| `getValidationErrors` | `Function` |  |  |  |

The custom numeric editor in the example below demonstrates the `useGridCellEditor` hook:

#### useGridCellEditor Example

```tsx
'use client';
import React, { StrictMode, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";

import type { ColDef } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  CustomEditorModule,
  TextEditorModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import NumericEditor from "./numericEditor";
import "./styles.css";

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

const modules = [
  TextEditorModule,
  TextFilterModule,
  CustomEditorModule,
  ClientSideRowModelModule,
];

const GridExample = () => {
  const [rowData] = useState([
    { name: "Bob", mood: "Happy", number: 10 },
    { name: "Harry", mood: "Sad", number: 3 },
    { name: "Sally", mood: "Happy", number: 20 },
    { name: "Mary", mood: "Sad", number: 5 },
    { name: "John", mood: "Happy", number: 15 },
    { name: "Jack", mood: "Happy", number: 25 },
    { name: "Sue", mood: "Sad", number: 43 },
    { name: "Sean", mood: "Sad", number: 1335 },
    { name: "Niall", mood: "Happy", number: 2 },
    { name: "Alberto", mood: "Happy", number: 123 },
    { name: "Fred", mood: "Sad", number: 532 },
    { name: "Jenny", mood: "Happy", number: 34 },
    { name: "Larry", mood: "Happy", number: 13 },
  ]);

  const columnDefs = useMemo<ColDef[]>(
    () => [
      {
        headerName: "Provided Text",
        field: "name",
        width: 300,
      },
      {
        headerName: "Custom Numeric",
        field: "number",
        cellEditor: NumericEditor,
        editable: true,
        width: 280,
      },
    ],
    [],
  );

  const defaultColDef = useMemo(
    () => ({
      editable: true,
      flex: 1,
      minWidth: 100,
      filter: true,
    }),
    [],
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={{ width: "100%", height: "100%" }}>
        <div
          style={{
            height: "100%",
            width: "100%",
          }}
        >
          <AgGridReact
            columnDefs={columnDefs}
            rowData={rowData}
            defaultColDef={defaultColDef}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: useGridCellEditor Example](https://www.ag-grid.com/archive/36.2.0/examples/cell-editors/component-editor/reactFunctionalTs/)

## Selecting Components

Cell Editor Components are configured using the `cellEditor` property of the [Column Definition](https://www.ag-grid.com/archive/36.2.0/react-data-grid/column-definitions/).

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `cellEditor` | `any` |  |  |  |

```jsx
const [columnDefs, setColumnDefs] = useState([
    {
        field: 'name',
        editable: true,
        // uses a provided editor, referenced by name
        cellEditor: 'agTextCellEditor'
    },
    {
        field: 'name',
        editable: true,
        // uses a custom editor, referenced directly
        cellEditor: 'CustomEditorComp'
    },
]);

<AgGridReact columnDefs={columnDefs} />
```

See [Registering Custom Components](https://www.ag-grid.com/archive/36.2.0/react-data-grid/components/#registering-custom-components) for details on how to register your custom grid components.

## Dynamic Selection

The `colDef.cellEditorSelector` function allows setting different Editor Components for different Rows within a Column.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `cellEditorSelector` | `CellEditorSelectorFunc` |  |  |  |

The `params` passed to `cellEditorSelector` are the same as those passed to the Editor Component. Typically the selector will use this to check the row's contents and choose an editor accordingly.

The result is an object with `component` and `params` to use instead of `cellEditor` and `cellEditorParams`.

This following shows the Selector always returning back the provided Rich Select Editor:

```js
cellEditorSelector: params => {
    return {
        component: 'agRichSelectCellEditor',
        params: { values: ['Male', 'Female'] }
    };
}
```

However a selector only makes sense when a selection is made. The following demonstrates selecting between Cell Editors:

```js
cellEditorSelector: params => {

  if (params.data.type === 'age') {
    return {
      component: NumericCellEditor,
    }
  }

  if (params.data.type === 'gender') {
    return {
      component: 'agRichSelectCellEditor',
      params: {
        values: ['Male', 'Female']
      }
    }
  }

  if (params.data.type === 'mood') {
    return {
      component: MoodEditor,
      popup: true,
      popupPosition: 'under'
    }
  }

  return undefined
}
```

Here is a full example:

- The column 'Value' holds data of different types as shown in the column 'Type' (numbers/genders/moods).
- `colDef.cellEditorSelector` is a function that returns the name of the component to use to edit based on the type of data for that row
- Edit a cell by double clicking to observe the different editors used.

#### Dynamic Editor Component

```tsx
'use client';
import React, { StrictMode, useCallback, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";

import type {
  CellEditingStartedEvent,
  CellEditingStoppedEvent,
  CellEditorSelectorResult,
  ColDef,
  ICellEditorParams,
  RowEditingStartedEvent,
  RowEditingStoppedEvent,
} from "ag-grid-community";
import {
  ClientSideRowModelModule,
  NumberEditorModule,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RichSelectModule,
} from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import type { IRow } from "./data";
import { getData } from "./data";
import MoodEditor from "./moodEditor";
import NumericCellEditor from "./numericCellEditor";
import "./styles.css";

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

const modules = [
  NumberEditorModule,
  TextEditorModule,
  ClientSideRowModelModule,
  ColumnMenuModule,
  ContextMenuModule,
  ColumnsToolPanelModule,
  RichSelectModule,
];

const cellEditorSelector: (
  params: ICellEditorParams<IRow>,
) => CellEditorSelectorResult | undefined = (
  params: ICellEditorParams<IRow>,
) => {
  if (params.data.type === "age") {
    return {
      component: NumericCellEditor,
    };
  }
  if (params.data.type === "gender") {
    return {
      component: "agRichSelectCellEditor",
      params: {
        values: ["Male", "Female"],
      },
    };
  }
  if (params.data.type === "mood") {
    return {
      component: MoodEditor,
      popup: true,
      popupPosition: "under",
    };
  }
  return undefined;
};

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IRow[]>(getData());
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "type" },
    {
      field: "value",
      editable: true,
      cellEditorSelector: cellEditorSelector,
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      cellDataType: false,
    };
  }, []);

  const onRowEditingStarted = useCallback((event: RowEditingStartedEvent) => {
    console.log("never called - not doing row editing");
  }, []);

  const onRowEditingStopped = useCallback((event: RowEditingStoppedEvent) => {
    console.log("never called - not doing row editing");
  }, []);

  const onCellEditingStarted = useCallback((event: CellEditingStartedEvent) => {
    console.log("cellEditingStarted");
  }, []);

  const onCellEditingStopped = useCallback((event: CellEditingStoppedEvent) => {
    console.log("cellEditingStopped");
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IRow>
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            onRowEditingStarted={onRowEditingStarted}
            onRowEditingStopped={onRowEditingStopped}
            onCellEditingStarted={onCellEditingStarted}
            onCellEditingStopped={onCellEditingStopped}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Dynamic Editor Component](https://www.ag-grid.com/archive/36.2.0/examples/cell-editors/dynamic-editor-component/reactFunctionalTs/)

## Custom Props

The property `colDef.cellEditorParams` allows custom props to be passed to editors.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `cellEditorParams` | `any` |  |  |  |

```js
colDef = {
    cellEditor: MyCellEditor,
    cellEditorParams: {
        // make "country" value available to cell editor
        country: 'Ireland'
    },
    // ...other props
}
```

## Dynamic Props

The `colDef.cellEditorParams` function allows dynamic props independently of the Editor selection. For example you might have a 'City' column that has values based on the 'Country' column.

```js
cellEditorParams: params => {
    const selectedCountry = params.data.country;

    if (selectedCountry === 'Ireland') {
        return {
            values: ['Dublin', 'Cork', 'Galway']
        };
    } else {
        return {
            values: ['New York', 'Los Angeles', 'Chicago', 'Houston']
        };
    }
}
```

Below shows an example with dynamic props. The following can be noted:

- Column **Gender** uses a Cell Component for both the grid and the editor.
- Column **Country** allows country selection, with `cellHeight` being used to make each entry 50px tall. If the currently selected city for the row doesn't match a newly selected country, the city cell is cleared.
- Column **City** uses dynamic parameters to display values for the selected country, and uses `formatValue` to add the selected city's country as a suffix.
- Column **Address** uses the large text area editor.

#### Dynamic Parameters

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  CellValueChangedEvent,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  ICellEditorParams,
  LargeTextEditorModule,
  ModuleRegistry,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RichSelectModule,
} from "ag-grid-enterprise";
import { IRow, getData } from "./data";
import GenderCellRenderer from "./genderCellRenderer.tsx";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RichSelectModule,
  TextEditorModule,
  LargeTextEditorModule,
];

const cellCellEditorParams = (params: ICellEditorParams<IRow>) => {
  const selectedCountry = params.data.country;
  const allowedCities = countyToCityMap(selectedCountry);
  return {
    values: allowedCities,
    formatValue: (value: any) => `${value} (${selectedCountry})`,
  };
};

const countyToCityMap: (match: string) => string[] = (match: string) => {
  const map: {
    [key: string]: string[];
  } = {
    Ireland: ["Dublin", "Cork", "Galway"],
    USA: ["New York", "Los Angeles", "Chicago", "Houston"],
  };
  return map[match];
};

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>(getData());
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "name" },
    {
      field: "gender",
      cellRenderer: GenderCellRenderer,
      cellEditor: "agRichSelectCellEditor",
      cellEditorParams: {
        values: ["Male", "Female"],
        cellRenderer: GenderCellRenderer,
      },
    },
    {
      field: "country",
      cellEditor: "agRichSelectCellEditor",
      cellEditorParams: {
        cellHeight: 50,
        values: ["Ireland", "USA"],
      },
    },
    {
      field: "city",
      cellEditor: "agRichSelectCellEditor",
      cellEditorParams: cellCellEditorParams,
    },
    {
      field: "address",
      cellEditor: "agLargeTextCellEditor",
      cellEditorPopup: true,
      minWidth: 550,
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 130,
      editable: true,
    };
  }, []);

  const onCellValueChanged = useCallback((params: CellValueChangedEvent) => {
    const colId = params.column.getId();
    if (colId === "country") {
      const selectedCountry = params.data.country;
      const selectedCity = params.data.city;
      const allowedCities = countyToCityMap(selectedCountry) || [];
      const cityMismatch = allowedCities.indexOf(selectedCity) < 0;
      if (cityMismatch) {
        params.node.setDataValue("city", null);
      }
    }
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            onCellValueChanged={onCellValueChanged}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Dynamic Parameters](https://www.ag-grid.com/archive/36.2.0/examples/cell-editors/dynamic-parameters/reactFunctionalTs/)

## Popup Editor

An editor can be Inline or Popup.

An Inline Editor Component will be placed inside the Grid's Cell, replacing the Cell contents when active.

A Popup Editor Component appears in a popup over the Cell. Popup Editors are not constrained to the Cells dimensions.

Configure that an Editor is in a popup by setting `cellEditorPopup=true` on the [Column Definition](https://www.ag-grid.com/archive/36.2.0/react-data-grid/column-definitions/).

```jsx
colDefs = [
  {
    cellEditor: MyPopupEditor,
    cellEditorPopup: true
    // ...
  }
]
```

Popup Editors appear over the editing Cell. Configure the Popup Editor to appear below the Cell by setting `cellEditorPopupPosition='under'` on the [Column Definition](https://www.ag-grid.com/archive/36.2.0/react-data-grid/column-definitions/).

```jsx
colDef = {
  cellEditorPopup: true,
  cellEditorPopupPosition: 'under',
  // ...other props
}
```

The following example demonstrates the same editor positioned inline, as a popup over the cell, and as a popup under the cell:

#### Popup Editor Components

```tsx
'use client';
import React, { StrictMode, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";

import type { ColDef } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  CustomEditorModule,
  NumberEditorModule,
  TextEditorModule,
  enableDevValidations,
} from "ag-grid-community";
import { RichSelectModule } from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import { getData } from "./data";
import MoodEditor from "./moodEditor";
import MoodRenderer from "./moodRenderer";
import "./styles.css";

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

const modules = [
  NumberEditorModule,
  TextEditorModule,
  CustomEditorModule,
  ClientSideRowModelModule,
  RichSelectModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>(getData());
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    {
      field: "mood",
      headerName: "Inline",
      cellRenderer: MoodRenderer,
      cellEditor: MoodEditor,
    },
    {
      field: "mood",
      headerName: "Popup Over",
      cellRenderer: MoodRenderer,
      cellEditor: MoodEditor,
      cellEditorPopup: true,
    },
    {
      field: "mood",
      headerName: "Popup Under",
      cellRenderer: MoodRenderer,
      cellEditor: MoodEditor,
      cellEditorPopup: true,
      cellEditorPopupPosition: "under",
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      editable: true,
      flex: 1,
      minWidth: 100,
    };
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Popup Editor Components](https://www.ag-grid.com/archive/36.2.0/examples/cell-editors/popup-editor/reactFunctionalTs/)

> **Note**
>
> If a custom cell editor creates its own popup that is anchored outside of the editor component (e.g. like a third-party date picker), then the popup element needs to have the `'ag-custom-component-popup'` CSS class. This allows the grid to determine correctly when to stop editing.

## Keyboard Navigation

In Custom Editors, you may wish to disable some of the Grids keyboard navigation. For example, if you are providing a simple text editor, you may wish the grid to do nothing when you press the right and left arrows (the default is the grid will move to the next / previous cell) as you may want the right and left arrows to move the cursor inside your editor. In other cell editors, you may wish the grid to behave as normal.

Because different cell editors will have different requirements on what the grid does, it is up to the cell editor to decide which event it wants the grid to handle and which it does not.

You have two options to stop the grid from doing it's default action on certain key events:

1. Stop propagation of the event to the grid in the cell editor.
2. Tell the grid to do nothing via the `colDef.suppressKeyboardEvent()` callback.

### Option 1 - Stop Propagation

If you don't want the grid to act on an event, call `event.stopPropagation()`. The advantage of this method is that your cell editor takes care of everything, this is good for creating reusable cell editors.

The following code snippet is one you could include for a simple text editor, which would stop the grid from doing navigation.

```jsx
const KEY_LEFT = 'ArrowLeft';
const KEY_UP = 'ArrowUp';
const KEY_RIGHT = 'ArrowRight';
const KEY_DOWN = 'ArrowDown';
const KEY_PAGE_UP = 'PageUp';
const KEY_PAGE_DOWN = 'PageDown';
const KEY_PAGE_HOME = 'Home';
const KEY_PAGE_END = 'End';

const MyCellEditor = ({ value, onValueChange }) => {
    const onKeyDown = (event) => {
        const key = event.key;

        const isNavigationKey = key === KEY_LEFT ||
            key === KEY_RIGHT ||
            key === KEY_UP ||
            key === KEY_DOWN ||
            key === KEY_PAGE_DOWN ||
            key === KEY_PAGE_UP ||
            key === KEY_PAGE_HOME ||
            key === KEY_PAGE_END;

        if (isNavigationKey) {
            // this stops the grid from receiving the event and executing keyboard navigation
            event.stopPropagation();
        }
    }

    return (
        <input
            value={value || ''}
            onChange={({ target: { value: newValue }) => onValueChange(newValue)}
            onKeyDownCapture={onKeyDown}
        />
    );
});
```

### Option 2 - Suppress Keyboard Event

If you implement `colDef.suppressKeyboardEvent()`, you can tell the grid which events you want to process and which not. The advantage of this method of the previous method is it takes the responsibility out of the cell editor and into the column definition. So if you are using a reusable, or third party, cell editor, and the editor doesn't have this logic in it, you can add the logic via configuration.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `suppressKeyboardEvent` | `SuppressKeyboardEventFunc` |  |  |  |

```jsx
const KEY_UP = 'ArrowUp';
const KEY_DOWN = 'ArrowDown';

const GridExample = () => {
    // rest of the component

    const columnDefs = [
        {
            field: 'value',
            suppressKeyboardEvent: params => {
                console.log('cell is editing: ' + params.editing);
                console.log('keyboard event:', params.event);

                // return true (to suppress) if editing and user hit up/down keys
                const key = params.event.key;
                const gridShouldDoNothing = params.editing && (key === KEY_UP || key === KEY_DOWN);
                return gridShouldDoNothing;
            }
        }
    ];

    return (
        <div
            style={{
                height: '100%',
                width: '100%'
            }}
            className="test-grid">
            <AgGridReact columnDefs={columnDefs} {/* ...rest of the definition... */} />
        </div>
    );
};
```

## Accessing Instances

After the grid has created an instance of an Editor Component for a Cell it is possible to access that instance. This is useful if you want to call a method that you provide on the Editor that has nothing to do with the operation of the grid. Accessing Editors is done using the grid API `getCellEditorInstances(params)`.

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

If you are doing normal editing, then only one cell is editable at any given time. For this reason if you call `getCellEditorInstances()` with no params, it will return back the editing cell's editor if a cell is editing, or an empty list if no cell is editing.

An example of calling `getCellEditorInstances()` is as follows:

```js
const instances = api.getCellEditorInstances(params);
if (instances.length > 0) {
    getInstance(instances[0], instance => {
        ...
    });
}
```

The example below shows using `getCellEditorInstances`. The following can be noted:

- All cells are editable.
- **First Name** and **Last Name** use the default editor.
- All other columns use the provided `MySimpleCellEditor` editor.
- The example sets an interval to print information from the active cell editor. There are three results: 1) No editing 2) Editing with default cell renderer and 3) editing with the custom cell editor. All results are printed to the developer console.

#### Get Editor Instance

```tsx
'use client';
import React, {
  StrictMode,
  useCallback,
  useMemo,
  useRef,
  useState,
} from "react";
import { createRoot } from "react-dom/client";

import type { ColDef, GridReadyEvent, ICellEditor } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  CustomEditorModule,
  NumberEditorModule,
  TextEditorModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import { AgGridProvider, AgGridReact, getInstance } from "ag-grid-react";

import type { MySimpleInterface } from "./mySimpleEditor";
import MySimpleEditor from "./mySimpleEditor";
import "./style.css";

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

const modules = [
  NumberEditorModule,
  TextEditorModule,
  TextFilterModule,
  CustomEditorModule,
  ClientSideRowModelModule,
];

const createRowData = () => {
  const cloneObject = (obj: any) => JSON.parse(JSON.stringify(obj));
  const students = [
    {
      first_name: "Bob",
      last_name: "Harrison",
      gender: "Male",
      address:
        "1197 Thunder Wagon Common, Cataract, RI, 02987-1016, US, (401) 747-0763",
      mood: "Happy",
      country: "Ireland",
    },
    {
      first_name: "Mary",
      last_name: "Wilson",
      gender: "Female",
      age: 11,
      address: "3685 Rocky Glade, Showtucket, NU, X1E-9I0, CA, (867) 371-4215",
      mood: "Sad",
      country: "Ireland",
    },
    {
      first_name: "Zahid",
      last_name: "Khan",
      gender: "Male",
      age: 12,
      address:
        "3235 High Forest, Glen Campbell, MS, 39035-6845, US, (601) 638-8186",
      mood: "Happy",
      country: "Ireland",
    },
    {
      first_name: "Jerry",
      last_name: "Mane",
      gender: "Male",
      age: 12,
      address:
        "2234 Sleepy Pony Mall , Drain, DC, 20078-4243, US, (202) 948-3634",
      mood: "Happy",
      country: "Ireland",
    },
  ];
  students.forEach((item) => {
    students.push(cloneObject(item));
  });
  students.forEach((item) => {
    students.push(cloneObject(item));
  });
  students.forEach((item) => {
    students.push(cloneObject(item));
  });
  return students;
};

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const [rowData] = useState<any[]>(createRowData());
  const columnDefs = useMemo<ColDef[]>(
    () => [
      {
        field: "first_name",
        headerName: "First Name",
        width: 120,
        editable: true,
      },
      {
        field: "last_name",
        headerName: "Last Name",
        width: 120,
        editable: true,
      },
      {
        field: "gender",
        width: 100,
        cellEditor: MySimpleEditor,
      },
      {
        field: "age",
        width: 80,
        cellEditor: MySimpleEditor,
      },
      {
        field: "mood",
        width: 90,
        cellEditor: MySimpleEditor,
      },
      {
        field: "country",
        width: 110,
        cellEditor: MySimpleEditor,
      },
      {
        field: "address",
        minWidth: 502,
        cellEditor: MySimpleEditor,
      },
    ],
    [],
  );

  const onGridReady = useCallback((params: GridReadyEvent) => {
    if (gridRef.current) {
      const interval = window.setInterval(() => {
        const instances = params.api.getCellEditorInstances();
        if (instances.length > 0) {
          getInstance<ICellEditor, MySimpleInterface>(
            instances[0],
            (instance) => {
              if (instance && instance.myCustomFunction) {
                const result = instance.myCustomFunction();
                console.log(
                  `found editing cell: row index = ${result.rowIndex}, column = ${result.colId}.`,
                );
              } else {
                console.log(
                  "found editing cell, but method myCustomFunction not found, must be the default editor.",
                );
              }
            },
          );
        } else {
          console.log("found not editing cell.");
        }
      }, 1000);

      return () => clearInterval(interval);
    }
  }, []);

  const defaultColDef = useMemo(
    () => ({
      editable: true,
      flex: 1,
      minWidth: 100,
      filter: true,
    }),
    [],
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={{ width: "100%", height: "100%" }}>
        <div
          style={{
            height: "100%",
            width: "100%",
          }}
        >
          <AgGridReact
            ref={gridRef}
            defaultColDef={defaultColDef}
            rowData={rowData}
            columnDefs={columnDefs}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

[Live example: Get Editor Instance](https://www.ag-grid.com/archive/36.2.0/examples/cell-editors/get-editor-instance/reactFunctionalTs/)

## API Reference

### CustomCellEditorProps

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

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `initialValue` | `TValue \| null \| undefined` |  |  |  |
| `value` | `TValue \| null \| undefined` |  |  |  |
| `onValueChange` | `Function` |  |  |  |
| `parseValue` | `Function` |  |  |  |
| `formatValue` | `Function` |  |  |  |
| `eventKey` | `string \| null` |  |  |  |
| `column` | `Column` |  |  |  |
| `colDef` | `ColDef` |  |  |  |
| `node` | `IRowNode` |  |  |  |
| `data` | `TData` |  |  |  |
| `rowIndex` | `number` |  |  |  |
| `cellStartedEdit` | `boolean` |  |  |  |
| `onKeyDown` | `Function` |  |  |  |
| `stopEditing` | `Function` |  |  |  |
| `eGridCell` | `HTMLElement` |  |  |  |
| `getValidationErrors` | `Function` |  |  |  |
| `validate` | `Function` |  |  |  |
| `api` | `GridApi` |  |  |  |
| `context` | `TContext` |  |  |  |
