---
title: "Tool Panel Component"
enterprise: true
framework: react
version: "36.1.0"
---

# Tool Panel Component

Custom Tool Panel Components can be included into the grid's Side Bar. Implement these when you require more Tool Panels to meet your application requirements.

The example below provides a 'Custom Stats' Tool Panel to demonstrates how to create and register a Custom Tool Panel Component with the grid and include it the Side Bar:

#### Custom Stats

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

import type {
  CellValueChangedEvent,
  ColDef,
  SideBarDef,
} from "ag-grid-community";
import {
  ClientSideRowModelApiModule,
  ClientSideRowModelModule,
  EventApiModule,
  NumberEditorModule,
  NumberFilterModule,
  RowApiModule,
  TextEditorModule,
  TextFilterModule,
  enableDevValidations,
  iconOverrides,
  themeQuartz,
} from "ag-grid-community";
import {
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";

import CustomStatsToolPanel from "./customStatsToolPanel";
import type { IOlympicData } from "./interfaces";

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

const modules = [
  ClientSideRowModelApiModule,
  NumberEditorModule,
  TextEditorModule,
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  SetFilterModule,
  RowApiModule,
  EventApiModule,
];

const myTheme = themeQuartz.withPart(
  iconOverrides({
    type: "image",
    mask: true,
    icons: {
      // map of icon names to images
      "custom-stats": {
        svg: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g stroke="#7F8C8D" fill="none" fill-rule="evenodd"><path d="M10.5 6V4.5h-5v.532a1 1 0 0 0 .36.768l1.718 1.432a1 1 0 0 1 0 1.536L5.86 10.2a1 1 0 0 0-.36.768v.532h5V10"/><rect x="1.5" y="1.5" width="13" height="13" rx="2"/></g></svg>',
      },
    },
  }),
);

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete", width: 150, filter: "agTextColumnFilter" },
    { field: "age", width: 90 },
    { field: "country", width: 120 },
    { field: "year", width: 90 },
    { field: "date", width: 110 },
    { field: "gold", width: 100, filter: false },
    { field: "silver", width: 100, filter: false },
    { field: "bronze", width: 100, filter: false },
    { field: "total", width: 100, filter: false },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      editable: true,
      flex: 1,
      minWidth: 100,
      filter: true,
    };
  }, []);
  const icons = useMemo<{
    [key: string]: ((...args: any[]) => any) | string;
  }>(() => {
    return {
      "custom-stats": '<span class="ag-icon ag-icon-custom-stats"></span>',
    };
  }, []);
  const sideBar = useMemo<
    SideBarDef | string | string[] | boolean | null
  >(() => {
    return {
      toolPanels: [
        {
          id: "columns",
          labelDefault: "Columns",
          labelKey: "columns",
          iconKey: "columns",
          toolPanel: "agColumnsToolPanel",
        },
        {
          id: "filters",
          labelDefault: "Filters",
          labelKey: "filters",
          iconKey: "filter",
          toolPanel: "agFiltersToolPanel",
        },
        {
          id: "customStats",
          labelDefault: "Custom Stats",
          labelKey: "customStats",
          iconKey: "custom-stats",
          toolPanel: CustomStatsToolPanel,
          toolPanelParams: {
            title: "Custom Stats",
          },
        },
      ],
      defaultToolPanel: "customStats",
    };
  }, []);

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

  const onCellValueChanged = useCallback((params: CellValueChangedEvent) => {
    params.api.refreshClientSideRowModel();
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={{ height: "100%", boxSizing: "border-box" }}>
          <div style={gridStyle}>
            <AgGridReact<IOlympicData>
              theme={myTheme}
              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              icons={icons}
              sideBar={sideBar}
              onCellValueChanged={onCellValueChanged}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Custom Stats](https://www.ag-grid.com/examples/component-tool-panel/custom-stats/reactFunctionalTs)

## Implementing a Tool Panel Component

When a tool panel component is instantiated then the following will be made available on `props`:

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

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `state` | `TState \| undefined` |  |  | The current state for the component (used in grid state). Initially set to the same value as `initialState` |
| `onStateChange` | `Function` |  |  | If using grid state, callback that should be called every time the state in the component changes. If not using grid state, not required. |
| `initialState` | `TState` |  |  | The tool-panel-specific initial state as provided in grid options if applicable |
| `api` | [`GridApi`](https://www.ag-grid.com/react-data-grid/grid-api/) |  |  | The grid api. |
| `context` | [`TContext`](https://www.ag-grid.com/react-data-grid/typescript-generics/#context-tcontext) |  |  | Application context as set on `gridOptions.context`. |

> **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/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.

## Registering Tool Panel Components

Registering a Tool Panel component follows the same approach as any other custom components in the grid. For more details see: [Registering Custom Components](https://www.ag-grid.com/react-data-grid/components/#registering-custom-components).

Once the Tool Panel Component is registered with the grid it needs to be included into the Side Bar. The following snippet illustrates this:

```jsx
<AgGridReact
    sideBar: {{
        toolPanels: [
            {
                id: 'customStats',
                labelDefault: 'Custom Stats',
                labelKey: 'customStats',
                iconKey: 'custom-stats',
                toolPanel: CustomStatsToolPanel,
                toolPanelParams: {
                    // can pass any custom props here
                },
            }
        ]
    }}
      ...other props...
/>
```

For more details on the configuration properties above, refer to the [Side Bar Configuration](https://www.ag-grid.com/react-data-grid/side-bar/#sidebardef-configuration) section.
