---
title: "Find"
enterprise: true
framework: react
version: "36.1.0"
---

# Find

Find allows for values to be searched within the grid, with all matches highlighted and navigable, similar to find (`^ Ctrl` + `F`) within the browser.

> **Note**
>
> Find is only compatible with the [Client-Side Row Model](https://www.ag-grid.com/react-data-grid/row-models/).

## Enabling Find

### Using Quick Access Toolbar

The recommended way to display the Find input is as a [Quick Access Toolbar](https://www.ag-grid.com/react-data-grid/toolbar/) item. This keeps the Find UI integrated with the grid and requires no additional markup.

#### Find with Toolbar

```tsx
"use client";

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

import type { ColDef, GridReadyEvent } from "ag-grid-community";
import {
  ClientSideRowModelModule,
  enableDevValidations,
} from "ag-grid-community";
import { FindModule, ToolbarModule } from "ag-grid-enterprise";
import { AgGridReact } from "ag-grid-react";

import "./styles.css";

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

const modules = [FindModule, ToolbarModule, ClientSideRowModelModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
    { field: "year" },
    { field: "age", minWidth: 100 },
    { field: "gold", minWidth: 100 },
    { field: "silver", minWidth: 100 },
    { field: "bronze", minWidth: 100 },
  ]);

  const toolbar = useMemo(
    () => ({
      items: ["agFindToolbarItem" as const],
    }),
    [],
  );

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) => setRowData(data));
  }, []);

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

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

[Live example: Find with Toolbar](https://www.ag-grid.com/examples/find/find-toolbar/reactFunctionalTs)

The configuration used in the example above is:

```jsx
const toolbar = {
    items: ['agFindToolbarItem'],
};

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

### Using Grid Options

Find can also be enabled directly via the grid option `findSearchValue`, passing the text to search for.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `findSearchValue` | `string` |  |  | Text to find within the grid. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |

```jsx
const findSearchValue = 'rowing';

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

The grid API methods `findNext()`, `findPrevious()`, and `findGoTo(matchNumber)` can be used to move between the matches, or `findClearActive()` can be used to clear the active match.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `findNext` | `Function` |  |  | Go to the next match. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `findPrevious` | `Function` |  |  | Go to the previous match. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `findGoTo` | `Function` |  |  | Go to the provided match (first match is `1`). By default, if the provided match is already active, this will do nothing. If `force` is set to `true`, this will instead reset the active match to that provided (e.g. scroll the grid). Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `findClearActive` | `Function` |  |  | Clear the active match. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |

Changing the Find search value, changing the active match, or updates to the grid that cause changes to the visible cells (e.g. changing columns/rows) trigger the `findChanged` event. The event contains details on the active match, as well as the total number of matches.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `findChanged` | `FindChangedEvent` |  |  | Find details have changed (e.g. Find search value, active match, or updates to grid cells). |

The active match and the total number of matches can also be retrieved via the API.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `findGetTotalMatches` | `Function` |  |  | Get the total number of matches. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `findGetActiveMatch` | `Function` |  |  | Get the active match, or `undefined` if no active match. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |

#### Find

```tsx
"use client";

import React, {
  type ChangeEvent,
  type KeyboardEvent,
  StrictMode,
  useCallback,
  useMemo,
  useRef,
  useState,
} from "react";
import { createRoot } from "react-dom/client";

import {
  ClientSideRowModelModule,
  ColDef,
  FindChangedEvent,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import { FindModule } from "ag-grid-enterprise";
import { AgGridReact } from "ag-grid-react";

import "./styles.css";

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

ModuleRegistry.registerModules([FindModule, ClientSideRowModelModule]);

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport" },
    { field: "year" },
    { field: "age", minWidth: 100 },
    { field: "gold", minWidth: 100 },
    { field: "silver", minWidth: 100 },
    { field: "bronze", minWidth: 100 },
  ]);

  const goToRef = useRef<HTMLInputElement>(null);

  const [findSearchValue, setFindSearchValue] = useState<string>();

  const [activeMatchNum, setActiveMatchNum] = useState<string>();

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) => setRowData(data));
  }, []);

  const onFindChanged = useCallback((event: FindChangedEvent) => {
    const { activeMatch, totalMatches, findSearchValue } = event;
    setActiveMatchNum(
      findSearchValue?.length
        ? `${activeMatch?.numOverall ?? 0}/${totalMatches}`
        : "",
    );
    console.log("findChanged", event);
  }, []);

  const onInput = useCallback((event: ChangeEvent<HTMLInputElement>) => {
    setFindSearchValue(event.target.value);
  }, []);

  const onKeyDown = useCallback((event: KeyboardEvent) => {
    if (event.key === "Enter") {
      event.preventDefault();
      const backwards = event.shiftKey;
      if (backwards) {
        previous();
      } else {
        next();
      }
    }
  }, []);

  const next = useCallback(() => {
    gridRef.current!.api.findNext();
  }, []);

  const previous = useCallback(() => {
    gridRef.current!.api.findPrevious();
  }, []);

  const goToFind = useCallback(() => {
    const num = Number(goToRef.current?.value);
    if (isNaN(num) || num < 0) {
      return;
    }
    gridRef.current!.api.findGoTo(num);
  }, []);

  return (
    <div style={containerStyle}>
      <div className="example-wrapper">
        <div className="example-header">
          <div className="example-controls">
            <span>Find:</span>
            <input type="text" onInput={onInput} onKeyDown={onKeyDown} />
            <button onClick={previous}>Previous</button>
            <button onClick={next}>Next</button>
            <span>{activeMatchNum}</span>
          </div>
          <div className="example-controls">
            <span>Go to match:</span>
            <input type="number" ref={goToRef} />
            <button onClick={goToFind}>Go To</button>
          </div>
        </div>

        <div style={gridStyle}>
          <AgGridReact
            ref={gridRef}
            rowData={rowData}
            columnDefs={columnDefs}
            findSearchValue={findSearchValue}
            onGridReady={onGridReady}
            onFindChanged={onFindChanged}
          />
        </div>
      </div>
    </div>
  );
};

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

[Live example: Find](https://www.ag-grid.com/examples/find/find/reactFunctionalTs)

## Using Find with Cell Components

By default, Find searches within the [Formatted Value](https://www.ag-grid.com/react-data-grid/value-formatters/) of the cell, or the raw cell value if there is no Value Formatter. This is what is displayed in the cell by default.

[Cell Components](https://www.ag-grid.com/react-data-grid/component-cell-renderer/) may display text that does not appear in the cell value. To enable Find to search within this additional text, the `getFindText` callback can be implemented on the Column Definition. Find will search within this value for matches.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getFindText` | `GetFindTextFunc` |  |  | When using Find with custom cell renderers, this allows providing a custom value to search within. E.g. if the cell renderer is displaying text that is different from the cell formatted value. Returning `null` means Find will not search within the cell. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |

```jsx
const [columnDefs, setColumnDefs] = useState([
    {
        field: 'year',
        getFindText: params => `Year is ${params.value}`,
    }
]);

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

When providing a custom cell component, the component is responsible for highlighting any matches and active matches within the cell. The grid API provides the following methods to help with this.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `findGetNumMatches` | `Function` |  |  | Get the number of matches within the provided cell. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |
| `findGetParts` | `Function` |  |  | Get the parts of a cell value, including matches and active match. Used for custom cell components. Module: [`FindModule`](https://www.ag-grid.com/react-data-grid/modules/). |

The following example demonstrates a custom cell component in the `Year` column that implements match highlighting using the methods above. The find input is provided by the toolbar. The custom cell component reuses the grid CSS classes `ag-find-match` and `ag-find-active-match` to apply the same styling as the default grid cell component.

#### Find with Cell Components

```tsx
"use client";

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

import type {
  ColDef,
  FirstDataRenderedEvent,
  GetFindTextParams,
  GridReadyEvent,
} from "ag-grid-community";
import {
  ClientSideRowModelModule,
  enableDevValidations,
} from "ag-grid-community";
import { FindModule, ToolbarModule } from "ag-grid-enterprise";
import { AgGridReact } from "ag-grid-react";

import FindRenderer from "./findRenderer";
import "./styles.css";

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

const modules = [FindModule, ToolbarModule, ClientSideRowModelModule];

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    {
      field: "year",
      cellRenderer: FindRenderer,
      getFindText: (params: GetFindTextParams) => {
        const cellValue =
          params.getValueFormatted() ?? params.value?.toString();
        if (!cellValue?.length) {
          return null;
        }
        return `Year is ${cellValue}`;
      },
    },
  ]);

  const toolbar = useMemo(
    () => ({ items: ["agFindToolbarItem" as const] }),
    [],
  );

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) => setRowData(data));
  }, []);

  const onFirstDataRendered = useCallback((event: FirstDataRenderedEvent) => {
    event.api.findNext();
  }, []);

  return (
    <div style={containerStyle}>
      <div style={gridStyle}>
        <AgGridReact
          ref={gridRef}
          rowData={rowData}
          columnDefs={columnDefs}
          modules={modules}
          findSearchValue="e"
          toolbar={toolbar}
          onGridReady={onGridReady}
          onFirstDataRendered={onFirstDataRendered}
        />
      </div>
    </div>
  );
};

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

[Live example: Find with Cell Components](https://www.ag-grid.com/examples/find/find-cell-components/reactFunctionalTs)

> **Note**
>
> Find does not work with the [Animate Show Changed Cell Component](https://www.ag-grid.com/react-data-grid/change-cell-renderers/#animate-show-changed-cells) or the [Animate Slide Cell Component](https://www.ag-grid.com/react-data-grid/change-cell-renderers/#animate-slide-cells). If using these, provide a `getFindText` that returns `null` to exclude them from the search results. The same approach should also be used if manually specifying `agCheckboxCellRenderer`.

## Customising Find

Find can be customised by providing an object of type `FindOptions` to the grid option `findOptions`.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `currentPageOnly` | `boolean` |  |  | Match values in the current page only (when pagination enabled). |
| `caseSensitive` | `boolean` |  |  | Match case of values. |
| `searchDetail` | `boolean` |  |  | Perform searches across Detail Grids or Custom Detail Cells when using Master/Detail. |

```jsx
const findOptions = {
    caseSensitive: true,
    currentPageOnly: true,
};

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

The following example demonstrates performing a case sensitive search, and finding matches within the current page only:

#### Customising Find

```tsx
"use client";

import React, {
  ChangeEvent,
  StrictMode,
  useCallback,
  useMemo,
  useRef,
  useState,
} from "react";
import { createRoot } from "react-dom/client";

import type {
  ColDef,
  FindChangedEvent,
  FindOptions,
  GridReadyEvent,
} from "ag-grid-community";
import {
  ClientSideRowModelModule,
  PaginationModule,
  PinnedRowModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  FindModule,
  RowGroupingModule,
  RowGroupingPanelModule,
  ToolbarModule,
} from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import "./styles.css";

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

const modules = [
  FindModule,
  ToolbarModule,
  RowGroupingModule,
  RowGroupingPanelModule,
  PinnedRowModule,
  ClientSideRowModelModule,
  PaginationModule,
];

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const pinnedTopRowData = useMemo<any[]>(() => {
    return [{ athlete: "Top" }];
  }, []);
  const pinnedBottomRowData = useMemo<any[]>(() => {
    return [{ athlete: "Bottom" }];
  }, []);
  const [columnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "sport", rowGroup: true, hide: true },
    { field: "year" },
    { field: "age", minWidth: 100 },
    { field: "gold", minWidth: 100 },
    { field: "silver", minWidth: 100 },
    { field: "bronze", minWidth: 100 },
  ]);

  const defaultColDef = useMemo<ColDef>(() => {
    return {
      enableRowGroup: true,
    };
  }, []);
  const paginationPageSizeSelector = useMemo<number[] | boolean>(() => {
    return [5, 10];
  }, []);
  const [findOptions, setFindOptions] = useState<FindOptions>({
    caseSensitive: true,
    currentPageOnly: true,
  });

  const toolbar = useMemo(
    () => ({
      items: [
        "agRowGroupPanelToolbarItem" as const,
        "agFindToolbarItem" as const,
      ],
    }),
    [],
  );

  const goToRef = useRef<HTMLInputElement>(null);

  const [activeMatch, setActiveMatch] = useState<string>();

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: any[]) => setRowData(data));
  }, []);

  const onFindChanged = useCallback((event: FindChangedEvent) => {
    const { activeMatch } = event;
    setActiveMatch(
      activeMatch
        ? `Active match: { pinned: ${activeMatch.node.rowPinned}, row index: ${activeMatch.node.rowIndex}, column: ${activeMatch.column?.getColId()}, match number in cell: ${activeMatch.numInMatch} }`
        : "",
    );
  }, []);

  const goToFind = useCallback(() => {
    const num = Number(goToRef.current?.value);
    if (isNaN(num) || num < 0) {
      return;
    }
    gridRef.current!.api.findGoTo(num);
  }, []);

  const toggleCaseSensitive = useCallback(
    (event: ChangeEvent<HTMLInputElement>) => {
      const caseSensitive = event.target.checked;
      setFindOptions((oldFindOptions) => ({
        ...oldFindOptions,
        caseSensitive,
      }));
    },
    [],
  );

  const toggleCurrentPageOnly = useCallback(
    (event: ChangeEvent<HTMLInputElement>) => {
      const currentPageOnly = event.target.checked;
      setFindOptions((oldFindOptions) => ({
        ...oldFindOptions,
        currentPageOnly,
      }));
    },
    [],
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <div className="example-controls">
              <label>
                <span>caseSensitive:</span>
                <input
                  id="caseSensitive"
                  type="checkbox"
                  onChange={toggleCaseSensitive}
                  checked={findOptions.caseSensitive}
                />
              </label>
              <label>
                <span>currentPageOnly:</span>
                <input
                  id="currentPageOnly"
                  type="checkbox"
                  onChange={toggleCurrentPageOnly}
                  checked={findOptions.currentPageOnly}
                />
              </label>
            </div>
            <div className="example-controls">
              <span>Go to match:</span>
              <input type="number" ref={goToRef} />
              <button onClick={goToFind}>Go To</button>
            </div>
            <div>{activeMatch}</div>
          </div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              pinnedTopRowData={pinnedTopRowData}
              pinnedBottomRowData={pinnedBottomRowData}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              pagination={true}
              paginationPageSize={5}
              paginationPageSizeSelector={paginationPageSizeSelector}
              toolbar={toolbar}
              findOptions={findOptions}
              onGridReady={onGridReady}
              onFindChanged={onFindChanged}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Customising Find](https://www.ag-grid.com/examples/find/customising-find/reactFunctionalTs)

## Find with Master / Detail

When using [Master / Detail](https://www.ag-grid.com/react-data-grid/master-detail/), Find will not search within detail rows by default (either [Detail Grids](https://www.ag-grid.com/react-data-grid/master-detail-grids/) or [Custom Details](https://www.ag-grid.com/react-data-grid/master-detail-custom-detail/)). To enable Find to search within detail rows, set `searchDetail` within `findOptions` to `true`:

```jsx
const findOptions = {
    searchDetail: true,
};

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

### Detail Grids

If a row containing a Detail Grid is expanded, Find will automatically search within the Detail Grid. If the master row is not expanded, the grid does not exist yet, so Find does not know how many matches there are. Find cannot create all of the Detail Grids as there may be a very large number of them.

If you want Find to search within collapsed detail rows, then you must provide the `getFindMatches` callback to the `detailCellRendererParams` grid option. This tells Find how many matches are expected to be in the Detail Grid. If the active match moves to within the Detail Grid, the Detail Grid will automatically be expanded.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getFindMatches` | `GetFindMatches` |  |  | If using Find across Master / Detail and the Detail Grid is not open, this will be called to work out the number of matches that would be within the Detail Grid. |

The following example demonstrates Find across nested Master / Detail Grids:

#### Find with Detail Grids

```tsx
"use client";

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

import type {
  ColDef,
  FindOptions,
  FirstDataRenderedEvent,
  GetDetailRowDataParams,
  GetFindMatchesParams,
  GetRowIdParams,
  IDetailCellRendererParams,
} from "ag-grid-community";
import {
  ClientSideRowModelModule,
  RowApiModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  FindModule,
  MasterDetailModule,
  ToolbarModule,
} from "ag-grid-enterprise";
import { AgGridReact } from "ag-grid-react";

import { getData } from "./data";
import "./styles.css";

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

const modules = [
  FindModule,
  ToolbarModule,
  ClientSideRowModelModule,
  MasterDetailModule,
  RowApiModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData] = useState<any[]>(getData());
  const [columnDefs] = useState<ColDef[]>([
    { field: "a1", cellRenderer: "agGroupCellRenderer" },
    { field: "b1" },
  ]);
  const defaultColDef = useMemo<ColDef>(
    () => ({
      flex: 1,
    }),
    [],
  );

  const getRowId = useCallback((params: GetRowIdParams) => params.data.a1, []);

  const getFindMatches = useCallback((params: GetFindMatchesParams) => {
    const getMatchesForValue = params.getMatchesForValue;
    let numMatches = 0;
    const checkRow = (row: any) => {
      for (const key of Object.keys(row)) {
        if (key === "children") {
          row.children.forEach((child: any) => checkRow(child));
        } else {
          numMatches += getMatchesForValue(row[key]);
        }
      }
    };
    params.data.children.forEach(checkRow);
    return numMatches;
  }, []);

  const detailCellRendererParams = useMemo<Partial<IDetailCellRendererParams>>(
    () => ({
      // level 2 grid options
      detailGridOptions: {
        columnDefs: [
          { field: "a2", cellRenderer: "agGroupCellRenderer" },
          { field: "b2" },
        ],
        defaultColDef: {
          flex: 1,
        },
        masterDetail: true,
        detailRowHeight: 240,
        getRowId: (params: GetRowIdParams) => params.data.a2,
        findOptions: {
          searchDetail: true,
        },
        detailCellRendererParams: {
          // level 3 grid options
          detailGridOptions: {
            columnDefs: [
              { field: "a3", cellRenderer: "agGroupCellRenderer" },
              { field: "b3" },
            ],
            defaultColDef: {
              flex: 1,
            },
            getRowId: (params: GetRowIdParams) => params.data.a3,
          },
          getDetailRowData: (params: GetDetailRowDataParams) => {
            params.successCallback(params.data.children);
          },
          getFindMatches,
        } as IDetailCellRendererParams,
      },
      getDetailRowData: (params: GetDetailRowDataParams) => {
        params.successCallback(params.data.children);
      },
      getFindMatches,
    }),
    [],
  );

  const findOptions = useMemo<FindOptions>(
    () => ({
      searchDetail: true,
    }),
    [],
  );

  const toolbar = useMemo(
    () => ({ items: ["agFindToolbarItem" as const] }),
    [],
  );

  const onFirstDataRendered = useCallback((event: FirstDataRenderedEvent) => {
    event.api.getDisplayedRowAtIndex(0)?.setExpanded(true);
  }, []);

  return (
    <div style={containerStyle}>
      <div style={gridStyle}>
        <AgGridReact
          rowData={rowData}
          columnDefs={columnDefs}
          defaultColDef={defaultColDef}
          masterDetail
          getRowId={getRowId}
          detailCellRendererParams={detailCellRendererParams}
          findOptions={findOptions}
          toolbar={toolbar}
          modules={modules}
          onFirstDataRendered={onFirstDataRendered}
        />
      </div>
    </div>
  );
};

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

[Live example: Find with Detail Grids](https://www.ag-grid.com/examples/find/find-detail-grid/reactFunctionalTs)

### Custom Detail

For Find to work with Custom Detail Cells, Find needs to know how many matches are within the detail row. This is done by providing the `getFindMatches` callback to the `detailCellRendererParams` grid option. This tells Find how many matches are expected to be in the Custom Detail. If the active match moves to within the Custom Detail, the Custom Detail will automatically be expanded.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getFindMatches` | `GetFindMatches` |  |  | If using Find across Master / Detail, this will be called to work out the number of matches that would be within the custom detail cell. |

The Custom Detail Cell Component is responsible for highlighting matches, similar to [Custom Cell Components](#using-find-with-cell-components).

The following example demonstrates Find across Custom Details:

#### Find with Custom Details

```tsx
"use client";

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

import type {
  ColDef,
  FindDetailCellRendererParams,
  FindOptions,
  FirstDataRenderedEvent,
  GetFindMatchesParams,
  GridReadyEvent,
} from "ag-grid-community";
import {
  ClientSideRowModelModule,
  RowApiModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  FindModule,
  MasterDetailModule,
  ToolbarModule,
} from "ag-grid-enterprise";
import { AgGridReact } from "ag-grid-react";

import DetailCellRenderer from "./detailCellRenderer";
import "./styles.css";

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

const modules = [
  FindModule,
  ToolbarModule,
  ClientSideRowModelModule,
  MasterDetailModule,
  RowApiModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>();
  const [columnDefs] = useState<ColDef[]>([
    // group cell renderer needed for expand / collapse icons
    { field: "name", cellRenderer: "agGroupCellRenderer" },
    { field: "account" },
    { field: "calls" },
  ]);

  const detailCellRenderer = useMemo(() => DetailCellRenderer, []);

  const detailCellRendererParams = useMemo<FindDetailCellRendererParams>(
    () => ({
      getFindMatches: (params: GetFindMatchesParams) => {
        return params.getMatchesForValue("My Custom Detail");
      },
    }),
    [],
  );

  const findOptions = useMemo<FindOptions>(
    () => ({
      searchDetail: true,
    }),
    [],
  );

  const toolbar = useMemo(
    () => ({ items: ["agFindToolbarItem" as const] }),
    [],
  );

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/master-detail-data.json")
      .then((resp) => resp.json())
      .then((data: any[]) => setRowData(data));
  }, []);

  const onFirstDataRendered = useCallback((event: FirstDataRenderedEvent) => {
    event.api.getDisplayedRowAtIndex(0)?.setExpanded(true);
  }, []);

  return (
    <div style={containerStyle}>
      <div style={gridStyle}>
        <AgGridReact
          rowData={rowData}
          columnDefs={columnDefs}
          masterDetail
          detailCellRenderer={detailCellRenderer}
          detailCellRendererParams={detailCellRendererParams}
          detailRowHeight={100}
          findOptions={findOptions}
          toolbar={toolbar}
          modules={modules}
          onGridReady={onGridReady}
          onFirstDataRendered={onFirstDataRendered}
        />
      </div>
    </div>
  );
};

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

[Live example: Find with Custom Details](https://www.ag-grid.com/examples/find/find-custom-detail/reactFunctionalTs)

## Find with Full Width Rows

For Find to work with [Full Width Rows](https://www.ag-grid.com/react-data-grid/full-width-rows/), Find needs to know how many matches are within the row. This is done by providing the `getFindMatches` callback to the `fullWidthCellRendererParams` grid option. This tells Find how many matches are expected to be in the Full Width Row.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getFindMatches` | `GetFindMatches` |  |  | If using Find with full width rows, this will be called to work out the number of matches that would be within the full width row. |

The Full Width Row Component is responsible for highlighting matches, similar to [Custom Cell Components](#using-find-with-cell-components).

The following example demonstrates Find with Full Width Rows:

#### Find with Full Width Rows

```tsx
"use client";

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

import type {
  ColDef,
  FindFullWidthCellRendererParams,
  GetFindMatchesParams,
  IsFullWidthRowParams,
  RowHeightParams,
} from "ag-grid-community";
import {
  ClientSideRowModelModule,
  enableDevValidations,
} from "ag-grid-community";
import { FindModule, ToolbarModule } from "ag-grid-enterprise";
import { AgGridReact } from "ag-grid-react";

import { getData, getLatinText } from "./data";
import FullWidthCellRenderer from "./fullWidthCellRenderer";
import "./styles.css";

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

const modules = [FindModule, ToolbarModule, ClientSideRowModelModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData] = useState<any[]>(getData());
  const [columnDefs] = useState<ColDef[]>([
    { field: "name" },
    { field: "continent" },
    { field: "language" },
  ]);
  const defaultColDef = useMemo<ColDef>(
    () => ({
      flex: 1,
    }),
    [],
  );

  const isFullWidth = useCallback((data: any) => {
    // return true when country is Peru, France or Italy
    return ["Peru", "France", "Italy"].indexOf(data.name) >= 0;
  }, []);

  const getRowHeight = useCallback((params: RowHeightParams) => {
    // return 100px height for full width rows
    if (isFullWidth(params.data)) {
      return 100;
    }
  }, []);

  const isFullWidthRow = useCallback((params: IsFullWidthRowParams) => {
    return isFullWidth(params.rowNode.data);
  }, []);

  const fullWidthCellRenderer = useMemo(() => FullWidthCellRenderer, []);

  const fullWidthCellRendererParams = useMemo<FindFullWidthCellRendererParams>(
    () => ({
      getFindMatches: (params: GetFindMatchesParams) => {
        const getMatchesForValue = params.getMatchesForValue;
        // this example only implements searching across part of the renderer
        let numMatches = getMatchesForValue("Sample Text in a Paragraph");
        getLatinText().forEach((paragraph) => {
          numMatches += getMatchesForValue(paragraph);
        });
        return numMatches;
      },
    }),
    [],
  );

  const toolbar = useMemo(
    () => ({ items: ["agFindToolbarItem" as const] }),
    [],
  );

  return (
    <div style={containerStyle}>
      <div style={gridStyle}>
        <AgGridReact
          rowData={rowData}
          columnDefs={columnDefs}
          defaultColDef={defaultColDef}
          getRowHeight={getRowHeight}
          isFullWidthRow={isFullWidthRow}
          fullWidthCellRenderer={fullWidthCellRenderer}
          fullWidthCellRendererParams={fullWidthCellRendererParams}
          toolbar={toolbar}
          modules={modules}
        />
      </div>
    </div>
  );
};

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

[Live example: Find with Full Width Rows](https://www.ag-grid.com/examples/find/find-full-width/reactFunctionalTs)

## Find with Custom Group Row Component

Using Find with a [Custom Group Row Inner Component](https://www.ag-grid.com/react-data-grid/grouping-group-rows/#custom-inner-renderer) (`groupRowRendererParams.innerRenderer`) or a [Custom Group Row Component](https://www.ag-grid.com/react-data-grid/grouping-group-rows/#custom-cell-renderer) (`groupRowRenderer`) is similar to using [Using Find with Cell Components](#using-find-with-cell-components). If the component displays text that does not appear in the cell value, the `getFindText` callback can be implemented on the `groupRowRendererParams` grid option. Find will search within this value for matches.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getFindText` | `GetFindTextFunc` |  |  | When using Find with a custom group row renderer, this allows providing a custom value to search within. E.g. if the group row renderer is displaying text that is different from the formatted value. Returning `null` means Find will not search within the group row. |

```jsx
const groupRowRendererParams = {
    getFindText: params => `Group value is ${params.value}`,
};

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

## Content to Search

Find is designed to search within "visible" cell contents.

Searching is not performed within hidden columns. Columns not displayed due to [Column Groups](https://www.ag-grid.com/react-data-grid/column-groups/) being expanded/collapsed are counted as being hidden.

The rows are searched after filtering and sorting have been performed.

Searching will be performed within the children of [Collapsed Row Groups](https://www.ag-grid.com/react-data-grid/grouping-opening-groups/). When the active match is set to a child row within a collapsed group, the group is expanded (along with its parents if necessary).

When using [Row Pagination](https://www.ag-grid.com/react-data-grid/row-pagination/), searching will be performed across all pages by default.

See the [Customising Find](#customising-find) section for an example of using Find with Row Grouping, as well as how to customise behaviour for Pagination.

If data is mutated outside of the grid (e.g. not via grid options or API methods), Find will not re-run automatically. This would apply to situations where `api.refreshCells()` or `api.redrawRows()` are being used. To get Find to update, `api.findRefresh()` should be called after either of these API methods.
