---
product: "AG Grid"
title: "New Filters Tool Panel"
description: "The new allows accessing the grid's filters without needing to open up the column menu."
enterprise: true
framework: react
version: "36.3.0"
related:
    - title: "Side Bar"
      url: "https://www.ag-grid.com/archive/36.3.0/react-data-grid/side-bar/"
    - title: "Columns Tool Panel"
      url: "https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns/"
    - title: "Filters Tool Panel"
      url: "https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-filters/"
    - title: "Custom Panel"
      url: "https://www.ag-grid.com/archive/36.3.0/react-data-grid/component-tool-panel/"
llms: "https://www.ag-grid.com/archive/36.3.0/llms.txt"
---

# New Filters Tool Panel

The new **Filters Tool Panel** allows accessing the grid's filters without needing to open up the column menu.

## Enabling New Filters Tool Panel

#### New Filters Tool Panel

```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,
  DateFilterModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  SideBarDef,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  NewFiltersToolPanelModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";

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

const modules = [
  NumberFilterModule,
  DateFilterModule,
  ClientSideRowModelModule,
  NewFiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  SetFilterModule,
  TextFilterModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IOlympicData[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "age" },
    { field: "country" },
    { field: "date", minWidth: 180 },
    { field: "total" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
      filter: "agSelectableColumnFilter",
      floatingFilter: true,
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: IOlympicData[]) =>
        setRowData(
          data.map((rowData) => {
            const dateParts = rowData.date.split("/");
            const [year, month, day] = dateParts
              .reverse()
              .map((e) => parseInt(e, 10));
            const paddedDateTimeStrings = [month, day].map((e) =>
              e.toString().padStart(2, "0"),
            );
            const date = `${year}-${paddedDateTimeStrings[0]}-${paddedDateTimeStrings[1]}`;
            return {
              ...rowData,
              date,
            };
          }),
        ),
      );
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            sideBar={"filters-new"}
            enableFilterHandlers={true}
            suppressSetFilterByDefault={true}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: New Filters Tool Panel](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-filters-new/simple/reactFunctionalTs/)

To use the new Filters Tool Panel, set `enableFilterHandlers = true`, and use the `'filters-new'` [Side Bar Configuration](https://www.ag-grid.com/archive/36.3.0/react-data-grid/side-bar/#configuring-the-side-bar).

If a filter is set from anywhere outside of the tool panel, e.g. from the column menu, the filter will automatically be added to the tool panel. Once a filter appears in the tool panel, it will remain until it's removed from within the tool panel. Removing a filter from the tool panel also clears that filter.

## Using Buttons

The tool panel can be configured to have global [Apply, Clear, Reset and Cancel Buttons](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-applying/#apply-clear-reset-and-cancel-buttons). These behave the same as when used within an individual filter, but instead apply to all filters at once.

To use global buttons, every filter must first be configured to use the buttons. The global buttons can then be passed to the tool panel configuration when using `agNewFiltersToolPanel`, by passing an `IToolPanelNewFiltersCompParams` object:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `buttons` | `FilterAction[]` |  |  | Allows global buttons to be provided to the filter tool panel |

The example below demonstrates using buttons with the tool panel:

#### New Filters Tool Panel Buttons

```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,
  DateFilterModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  SelectableFilterParams,
  SideBarDef,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  NewFiltersToolPanelModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";

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

const modules = [
  NumberFilterModule,
  DateFilterModule,
  ClientSideRowModelModule,
  NewFiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  SetFilterModule,
  TextFilterModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IOlympicData[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "age" },
    { field: "country" },
    { field: "date", minWidth: 180 },
    { field: "total" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
      filter: "agSelectableColumnFilter",
      filterParams: {
        defaultFilterParams: {
          buttons: ["apply"], // set all filters to use buttons
        },
      } as SelectableFilterParams,
    };
  }, []);
  const sideBar = useMemo<
    SideBarDef | string | string[] | boolean | null
  >(() => {
    return {
      toolPanels: [
        {
          id: "filters-new",
          labelDefault: "Filters",
          labelKey: "filters",
          iconKey: "filter",
          toolPanel: "agNewFiltersToolPanel",
          toolPanelParams: {
            buttons: ["cancel", "apply"],
          },
        },
      ],
      defaultToolPanel: "filters-new",
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: IOlympicData[]) =>
        setRowData(
          data.map((rowData) => {
            const dateParts = rowData.date.split("/");
            const [year, month, day] = dateParts
              .reverse()
              .map((e) => parseInt(e, 10));
            const paddedDateTimeStrings = [month, day].map((e) =>
              e.toString().padStart(2, "0"),
            );
            const date = `${year}-${paddedDateTimeStrings[0]}-${paddedDateTimeStrings[1]}`;
            return {
              ...rowData,
              date,
            };
          }),
        ),
      );
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            sideBar={sideBar}
            enableFilterHandlers={true}
            suppressSetFilterByDefault={true}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: New Filters Tool Panel Buttons](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-filters-new/using-buttons/reactFunctionalTs/)

Note that when opened from the column menu, the buttons will be visible within the individual filters. Within the tool panel, only the global buttons will be visible.

## Configuring Filters

### Changing Selectable Filters

For each column filter, the filter type can be changed by using the dropdown within the tool panel. To enable switching filters, set `filter: 'agSelectableColumnFilter'` on the column definition. For any other `filter` value, the dropdown will not be displayed.

By default, the dropdown will allow switching between:

- `Simple Filter` - [Text Filter](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-text/), [Number Filter](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-number/), [BigInt Filter](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-bigint/) or [Date Filter](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-date/), depending on the [Cell Data Type](https://www.ag-grid.com/archive/36.3.0/react-data-grid/cell-data-types/)
- `Selection Filter` - [Set Filter](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-set/)
- `Combo Filter` - [Multi Filter](https://www.ag-grid.com/archive/36.3.0/react-data-grid/filter-multi/) (if the `MultiFilterModule` is loaded)

To allow other filters to be configured in the dropdown, `filterParams` of type `SelectableFilterParams` can be set on the column definition:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `filters` | `SelectableFilterDef[]` |  |  | List of possible filters which will show in the filter card. If not provided, will default to grid-provided filters |
| `defaultFilterIndex` | `number` |  |  | The index of the filter that should be active by default, in `filters` or else in the default list. Without one the first is active, except that the default list starts at its Set Filter where that is the default filter. An index naming no filter selects the first. |
| `defaultFilterParams` | `FilterWrapperParams` |  |  | Params which will be passed to all filters |

### Suppressing Filters

To remove a particular column / filter from the tool panel, set the column property `suppressFiltersToolPanel` to `true`.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `suppressFiltersToolPanel` | `boolean` |  | `false` | Set to `true` if you do not want this column (filter) or group (filter group) to appear in the Filters Tool Panel. [Module](https://www.ag-grid.com/archive/36.3.0/react-data-grid/modules/): `ColumnsToolPanelModule`. |

### Example: Configuring Filters

The example below demonstrates configuring filters:

- The **Athlete** column does not show a dropdown as it has `filter: 'agSetColumnFilter'` set.
- The **Age** column shows all three grid-provided filter options by default.
- The **Country** column is configured to show the Set Filter before the Text Filter.
- The **Year** column is configured to show a custom filter component with the Set Filter.
- The **Date** column has `suppressFiltersToolPanel: true` set, so it does not show in the tool panel.

#### New Filters Tool Panel Configuration

```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,
  DateFilterModule,
  DoesFilterPassParams,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  SelectableFilterParams,
  SideBarDef,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  MultiFilterModule,
  NewFiltersToolPanelModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import "./style.css";
import YearFilter from "./yearFilter.tsx";
import { IOlympicData } from "./interfaces";

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

const modules = [
  NumberFilterModule,
  DateFilterModule,
  ClientSideRowModelModule,
  NewFiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  SetFilterModule,
  TextFilterModule,
  MultiFilterModule,
];

const doesFilterPass: ({
  model,
  node,
  handlerParams,
}: DoesFilterPassParams<any, any, boolean>) => boolean = ({
  model,
  node,
  handlerParams,
}: DoesFilterPassParams<any, any, boolean>) => {
  return model ? handlerParams.getValue(node) > 2010 : true;
};

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<IOlympicData[]>();
  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete", filter: "agSetColumnFilter" },
    { field: "age" },
    {
      field: "country",
      filterParams: {
        filters: [
          {
            filter: "agSetColumnFilter",
          },
          {
            filter: true, // default filter based on cell data type
          },
        ],
      } as SelectableFilterParams,
    },
    {
      field: "year",
      filterParams: {
        filters: [
          {
            filter: { component: YearFilter, doesFilterPass: doesFilterPass },
            name: "Custom Filter",
          },
          {
            filter: "agSetColumnFilter",
          },
        ],
      } as SelectableFilterParams,
    },
    { field: "date", minWidth: 180, suppressFiltersToolPanel: true },
    { field: "total", filter: false },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
      filter: "agSelectableColumnFilter",
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .then((resp) => resp.json())
      .then((data: IOlympicData[]) =>
        setRowData(
          data.map((rowData) => {
            const dateParts = rowData.date.split("/");
            const [year, month, day] = dateParts
              .reverse()
              .map((e) => parseInt(e, 10));
            const paddedDateTimeStrings = [month, day].map((e) =>
              e.toString().padStart(2, "0"),
            );
            const date = `${year}-${paddedDateTimeStrings[0]}-${paddedDateTimeStrings[1]}`;
            return {
              ...rowData,
              date,
            };
          }),
        ),
      );
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={rowData}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            sideBar={"filters-new"}
            enableFilterHandlers={true}
            suppressSetFilterByDefault={true}
            onGridReady={onGridReady}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: New Filters Tool Panel Configuration](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-filters-new/configuring-filters/reactFunctionalTs/)

## Filters Tool Panel State

When the grid initialises, the tool panel only shows active filters provided in the [Initial State](https://www.ag-grid.com/archive/36.3.0/react-data-grid/grid-state/) filter model. The tool panel can also be configured via initial state to show inactive filters, or change the order and expansion state. This is provided to the Side Bar state as a `NewFiltersToolPanelState` object:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `filters` | `NewFiltersToolPanelFilterState[]` |  |  | Ordered list of filters and their expansion state |

### Managing Tool Panel State

The filter cards shown in the tool panel are part of the [Side Bar](https://www.ag-grid.com/archive/36.3.0/react-data-grid/side-bar/) state, which is separate from the filter model. Clearing the filter model with `api.setFilterModel(null)` therefore clears the filter values but leaves the (now inactive) cards in place.

To remove cards from the tool panel programmatically, see [Choosing Filter Cards](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-filters-new/#choosing-filter-cards).

A saved layout can be restored by passing a previously captured `sideBar` state to `api.setState`. Pass the `filter` state too to restore each card's values as well as the cards themselves. See [Grid State](https://www.ag-grid.com/archive/36.3.0/react-data-grid/grid-state/) for the full `getState` and `setState` semantics.

## Expand / Collapse Filter Cards

The filter cards in the tool panel can be expanded and collapsed by invoking methods on the Filters Tool Panel instance:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `expandFilterCards` | `Function` |  |  | Expands the filter cards with the supplied `colIds`, or all filter cards if not supplied. |
| `collapseFilterCards` | `Function` |  |  | Collapses the filter cards with the supplied `colIds`, or all filter cards if not supplied. |

```jsx
// expands the 'age' and 'country' filter cards
gridApi.getToolPanelInstance('filters-new').expandFilterCards(['age', 'country']);
```

Only filters which already have a card in the tool panel are affected.

## Choosing Filter Cards

`setFilterCards` sets exactly which filter cards are shown in the tool panel, and in what order. **Any column omitted from the list has its card removed, and its filter is cleared.** Passing an empty array (`[]`) removes every card and clears their filters.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `setFilterCards` | `Function` |  |  | Shows a filter card for each of the supplied `colIds`, in that order. Every other card is removed and its filter cleared. Existing cards keep their expanded state; new cards are collapsed. |
| `getState` | `Function` |  |  | If saving and restoring state, this should return the current state |

```jsx
// shows only the 'athlete', 'country' and 'year' cards, in that order
gridApi.getToolPanelInstance('filters-new').setFilterCards(['athlete', 'country', 'year']);
```

- Cards are shown in the order given.
- Cards that already exist keep their expanded state. Cards that are added are collapsed, unlike when added using **Add Filter** in the tool panel, which adds them expanded.
- Column IDs that do not match a column in the grid are skipped, and a warning is logged in development.

## Example: Managing Filter Cards

The example below starts with filters on Age and Country, and an inactive Athlete card:

- **Show Athlete, Country, Year** calls `setFilterCards(['athlete', 'country', 'year'])`. The Age card is removed and its filter is cleared. Country keeps its filter and expanded state, and Year is added collapsed.
- **Expand All** and **Collapse All** call `expandFilterCards()` and `collapseFilterCards()`.
- **Clear Filter Values** calls `api.setFilterModel(null)`. The rows are unfiltered, but the cards remain.
- **Remove Inactive** uses `getState` to find the current cards, and passes the ones with a filter to `setFilterCards`.
- **Remove All** calls `setFilterCards([])`. Every card is removed and the rows are unfiltered.
- **Save State** captures the current grid state with `api.getState()`.
- **Restore Saved State** applies the saved `filter` and `sideBar` state, restoring both the cards and their values.
- **Restore Initial State** applies the state the grid was created with.

#### Managing Filter Cards

```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,
  GridApi,
  GridOptions,
  GridState,
  GridStateModule,
  ModuleRegistry,
  NewFiltersToolPanelState,
  NumberFilterModule,
  SideBarDef,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ContextMenuModule,
  NewFiltersToolPanelModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import "./styles.css";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  NumberFilterModule,
  ClientSideRowModelModule,
  NewFiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  SetFilterModule,
  TextFilterModule,
  GridStateModule,
];

const initialGridState: GridState = {
  filter: {
    filterModel: {
      age: { filterType: "number", type: "lessThan", filter: 25 },
      country: { filterType: "set", values: ["United States", "Russia"] },
    },
  },
  sideBar: {
    visible: true,
    position: "right",
    openToolPanel: "filters-new",
    toolPanels: {
      "filters-new": {
        filters: [
          { colId: "athlete" },
          { colId: "age" },
          { colId: "country", expanded: true },
        ],
      } as NewFiltersToolPanelState,
    },
  },
};

let savedState: GridState | undefined;

const GridExample = () => {
  const gridRef = useRef<AgGridReact<IOlympicData>>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "age", filter: "agNumberColumnFilter" },
    { field: "country" },
    { field: "year", filter: "agNumberColumnFilter" },
    { field: "total", filter: "agNumberColumnFilter" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
      filter: true,
    };
  }, []);
  const initialState = useMemo<GridState>(() => {
    return initialGridState;
  }, []);

  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  const showAthleteCountryYear = useCallback(() => {
    gridRef
      .current!.api.getToolPanelInstance("filters-new")!
      .setFilterCards(["athlete", "country", "year"]);
  }, []);

  const expandAll = useCallback(() => {
    gridRef
      .current!.api.getToolPanelInstance("filters-new")!
      .expandFilterCards();
  }, []);

  const collapseAll = useCallback(() => {
    gridRef
      .current!.api.getToolPanelInstance("filters-new")!
      .collapseFilterCards();
  }, []);

  const clearFilterValues = useCallback(() => {
    // The cards are part of the Side Bar state, not the filter model, so they stay in place
    gridRef.current!.api.setFilterModel(null);
  }, []);

  const removeInactiveCards = useCallback(() => {
    const toolPanel = gridRef.current!.api.getToolPanelInstance("filters-new")!;
    const colIds = (toolPanel.getState().filters ?? []).map(
      ({ colId }) => colId,
    );
    // When using Apply buttons, a card can have changes that have not been applied yet,
    // so also check the unapplied model to keep those cards
    toolPanel.setFilterCards(
      colIds.filter(
        (colId) =>
          gridRef.current!.api.getColumnFilterModel(colId) != null ||
          gridRef.current!.api.getColumnFilterModel(colId, true) != null,
      ),
    );
  }, []);

  const removeAllCards = useCallback(() => {
    gridRef
      .current!.api.getToolPanelInstance("filters-new")!
      .setFilterCards([]);
  }, []);

  // `setState` resets any section of the grid state it is not given, so the handlers below
  // spread the current state to keep everything else (e.g. sorting) unchanged
  const saveState = useCallback(() => {
    savedState = gridRef.current!.api.getState();
    console.log("Saved state", savedState);
  }, [savedState]);

  const restoreSavedState = useCallback(() => {
    if (savedState) {
      // Restore the `filter` state as well as the `sideBar` state, to restore each card's values
      gridRef.current!.api.setState({
        ...gridRef.current!.api.getState(),
        filter: savedState.filter,
        sideBar: savedState.sideBar,
      });
      console.log("Restored state", savedState);
    }
  }, [savedState]);

  const restoreInitialState = useCallback(() => {
    gridRef.current!.api.setState({
      ...gridRef.current!.api.getState(),
      filter: initialGridState.filter,
      sideBar: initialGridState.sideBar,
    });
  }, [initialGridState]);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div>
            <span className="button-group">
              <span>Cards:</span>
              <button onClick={showAthleteCountryYear}>
                Show Athlete, Country, Year
              </button>
              <button onClick={expandAll}>Expand All</button>
              <button onClick={collapseAll}>Collapse All</button>
              <button onClick={clearFilterValues}>Clear Filter Values</button>
              <button onClick={removeInactiveCards}>Remove Inactive</button>
              <button onClick={removeAllCards}>Remove All</button>
            </span>
          </div>
          <div>
            <span className="button-group">
              <span>State:</span>
              <button onClick={saveState}>Save State</button>
              <button onClick={restoreSavedState}>Restore Saved State</button>
              <button onClick={restoreInitialState}>
                Restore Initial State
              </button>
            </span>
          </div>

          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              ref={gridRef}

              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              sideBar={"filters-new"}
              enableFilterHandlers={true}
              initialState={initialState}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Managing Filter Cards](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-filters-new/managing-filter-cards/reactFunctionalTs/)

## Filter Instances

The filters provided in the tool panel are the same instances as the filter in the column menu. This has the following implications:

- Configuration relating to filters equally applies when the filters appear in the tool panel.
- The filter behaves exactly as when it appears in the column menu. E.g. the Apply button will have the same meaning when used in the tool panel. Also the relationship with the Floating Filter (if active) will be the same.
- If the filter is open on the tool panel and then the user subsequently opens the column menu, the tool panel filter will be closed. Because the filter is the same filter instance, it will only appear at one location at any given time.
