---
title: "Formula Editor Component"
enterprise: true
framework: react
version: "36.1.0"
---

# Formula Editor Component

The Formula Cell Editor is the default editor for columns with `allowFormula: true`. It tokenises cell references, highlights ranges, and provides function autocomplete while you type.

## Default Formula Editor

If a column enables formulas and does not specify a `cellEditor`, the grid automatically uses the Formula Cell Editor.

#### Formula Editor

```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 {
  CellSelectionOptions,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GetRowIdParams,
  GridApi,
  GridOptions,
  ModuleRegistry,
  NumberEditorModule,
  TextEditorModule,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, FormulaModule } from "ag-grid-enterprise";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  CellSelectionModule,
  ClientSideRowModelModule,
  FormulaModule,
  NumberEditorModule,
  TextEditorModule,
];

const currencyFormatter = ({ value }: ValueFormatterParams) =>
  `$ ${Number(value).toFixed(2)}`;

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    {
      id: 1,
      item: "Apples",
      price: 1.2,
      qty: 4,
      total: '=REF(COLUMN("price"),ROW(1))*REF(COLUMN("qty"),ROW(1))',
    },
    {
      id: 2,
      item: "Bananas",
      price: 0.5,
      qty: 6,
      total: '=REF(COLUMN("price"),ROW(2))*REF(COLUMN("qty"),ROW(2))',
    },
    {
      id: 3,
      item: "Oranges",
      price: 0.8,
      qty: 3,
      total: '=REF(COLUMN("price"),ROW(3))*REF(COLUMN("qty"),ROW(3))',
    },
    {
      id: 4,
      item: "Pears",
      price: 1.4,
      qty: 2,
      total: '=REF(COLUMN("price"),ROW(4))*REF(COLUMN("qty"),ROW(4))',
    },
    {
      id: 5,
      item: "Grapes",
      price: 2.1,
      qty: 3,
      total: '=REF(COLUMN("price"),ROW(5))*REF(COLUMN("qty"),ROW(5))',
    },
    {
      id: 6,
      item: "Strawberries",
      price: 1.8,
      qty: 4,
      total: '=REF(COLUMN("price"),ROW(6))*REF(COLUMN("qty"),ROW(6))',
    },
  ]);
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "item" },
    { field: "price", valueFormatter: currencyFormatter },
    { field: "qty" },
    { field: "total", allowFormula: true, valueFormatter: currencyFormatter },
  ]);
  const getRowId = useCallback(
    (params: GetRowIdParams) => String(params.data.id),
    [],
  );
  const cellSelection = useMemo<boolean | CellSelectionOptions>(() => {
    return {
      handle: {
        mode: "fill",
      },
    };
  }, []);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      editable: true,
      flex: 1,
    };
  }, []);

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

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

[Live example: Formula Editor](https://www.ag-grid.com/examples/formula-editor-component/formula-editor-component/reactFunctionalTs/)

> **Note**
>
> Range highlights and range handle editing require `cellSelection` to be enabled. Without it, the editor still works but range highlights and handles are not shown.

## Disabling the Formula Cell Editor

Providing a `cellEditor` opts the column out of the Formula Cell Editor. Formulas still evaluate, but range highlighting, handles, and function autocomplete are disabled because a different editor is in use.

#### Formula Editor Disabled

```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 {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GetRowIdParams,
  GridApi,
  GridOptions,
  ModuleRegistry,
  NumberEditorModule,
  TextEditorModule,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import { FormulaModule } from "ag-grid-enterprise";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  FormulaModule,
  NumberEditorModule,
  TextEditorModule,
];

const valueFormatter = ({ value }: ValueFormatterParams) =>
  `$ ${Number(value).toFixed(2)}`;

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    {
      id: 1,
      item: "Apples",
      price: 1.2,
      qty: 4,
      total: '=REF(COLUMN("price"),ROW(1))*REF(COLUMN("qty"),ROW(1))',
    },
    {
      id: 2,
      item: "Bananas",
      price: 0.5,
      qty: 6,
      total: '=REF(COLUMN("price"),ROW(2))*REF(COLUMN("qty"),ROW(2))',
    },
    {
      id: 3,
      item: "Oranges",
      price: 0.8,
      qty: 3,
      total: '=REF(COLUMN("price"),ROW(3))*REF(COLUMN("qty"),ROW(3))',
    },
    {
      id: 4,
      item: "Pears",
      price: 1.4,
      qty: 2,
      total: '=REF(COLUMN("price"),ROW(4))*REF(COLUMN("qty"),ROW(4))',
    },
    {
      id: 5,
      item: "Grapes",
      price: 2.1,
      qty: 3,
      total: '=REF(COLUMN("price"),ROW(5))*REF(COLUMN("qty"),ROW(5))',
    },
    {
      id: 6,
      item: "Strawberries",
      price: 1.8,
      qty: 4,
      total: '=REF(COLUMN("price"),ROW(6))*REF(COLUMN("qty"),ROW(6))',
    },
  ]);
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "item" },
    { field: "price", valueFormatter },
    { field: "qty" },
    {
      field: "total",
      allowFormula: true,
      cellEditor: "agTextCellEditor",
      valueFormatter,
    },
  ]);
  const getRowId = useCallback(
    (params: GetRowIdParams) => String(params.data.id),
    [],
  );
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      editable: true,
      flex: 1,
    };
  }, []);

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

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

[Live example: Formula Editor Disabled](https://www.ag-grid.com/examples/formula-editor-component/formula-editor-component-disabled/reactFunctionalTs/)

## Validation

Invalid formulas already surface via the formula engine: the cell displays the error and shows a tooltip based on the grid's formula error state. Because of this, the Formula Cell Editor does not validate on every change by default.

To opt into validation while editing, set `validateFormulas: true` on the editor params. Validation will also run if you provide a custom [getValidationErrors](https://www.ag-grid.com/react-data-grid/cell-editing-validation/#overriding-validation) callback. For more details on validation behaviour and presentation, see [Cell Editing Validation](https://www.ag-grid.com/react-data-grid/cell-editing-validation/).

```js
const columnDefs = [
    {
        field: 'total',
        allowFormula: true,
        cellEditorParams: {
            validateFormulas: true,
        },
    },
];
```

#### Formula Editor Validation

```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 {
  CellSelectionOptions,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetRowIdFunc,
  GetRowIdParams,
  GridApi,
  GridOptions,
  ModuleRegistry,
  NumberEditorModule,
  TextEditorModule,
  ValueFormatterParams,
  enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, FormulaModule } from "ag-grid-enterprise";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  CellSelectionModule,
  ClientSideRowModelModule,
  FormulaModule,
  NumberEditorModule,
  TextEditorModule,
];

const valueFormatter = ({ value }: ValueFormatterParams) => {
  if (typeof value === "string" && value.startsWith("#")) {
    return value;
  }
  const numericValue = Number(value);
  return Number.isFinite(numericValue)
    ? `$ ${numericValue.toFixed(2)}`
    : String(value ?? "");
};

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    {
      id: 1,
      item: "Apples",
      price: 1.2,
      qty: 4,
      total: '=REF(COLUMN("price"),ROW(1))*REF(COLUMN("qty"),ROW(1))',
    },
    {
      id: 2,
      item: "Bananas",
      price: 0.5,
      qty: 6,
      total: "=B2*",
    },
    {
      id: 3,
      item: "Oranges",
      price: 0.8,
      qty: 3,
      total: '=REF(COLUMN("price"),ROW(3))*REF(COLUMN("qty"),ROW(3))',
    },
    {
      id: 4,
      item: "Pears",
      price: 1.4,
      qty: 2,
      total: '=REF(COLUMN("price"),ROW(4))*REF(COLUMN("qty"),ROW(4))',
    },
    {
      id: 5,
      item: "Grapes",
      price: 2.1,
      qty: 3,
      total: "=BADFUNC(1)",
    },
    {
      id: 6,
      item: "Plums",
      price: 1.5,
      qty: 2,
      total: '=REF(COLUMN("price"),ROW(6))*REF(COLUMN("qty"),ROW(6))',
    },
    {
      id: 7,
      item: "Strawberries",
      price: 1.8,
      qty: 4,
      total: '=REF(COLUMN("price"),ROW(7))*REF(COLUMN("qty"),ROW(7))',
    },
  ]);
  const getRowId = useCallback(
    (params: GetRowIdParams) => String(params.data.id),
    [],
  );
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "item" },
    { field: "price", valueFormatter: valueFormatter },
    { field: "qty" },
    {
      field: "total",
      allowFormula: true,
      valueFormatter: valueFormatter,
      cellEditorParams: {
        validateFormulas: true,
      },
    },
  ]);
  const cellSelection = useMemo<boolean | CellSelectionOptions>(() => {
    return {
      handle: {
        mode: "fill",
      },
    };
  }, []);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      editable: true,
      flex: 1,
    };
  }, []);

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

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

[Live example: Formula Editor Validation](https://www.ag-grid.com/examples/formula-editor-component/formula-editor-component-validation/reactFunctionalTs/)
