---
product: "AG Grid"
title: "Columns Tool Panel - Customisation"
description: "Customise how columns appear in the Columns Tool Panel: their styling and names, custom label renderers, expanding and collapsing column groups, the context menu and the drag image."
enterprise: true
framework: react
version: "36.3.0"
related:
    - title: "Configuration"
      url: "https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-configuration/"
    - title: "Deferred Updates"
      url: "https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-deferred-updates/"
llms: "https://www.ag-grid.com/archive/36.3.0/llms.txt"
---

# Columns Tool Panel - Customisation

Customise how columns appear in the Columns Tool Panel: their styling and names, custom label renderers, expanding and collapsing column groups, the context menu and the drag image.

## Styling Columns

The example below styles the `gold`, `silver` and `bronze` columns using `toolPanelClass`.

#### Tool Panel Styling

```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 {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  HeaderValueGetterParams,
  ModuleRegistry,
  NumberFilterModule,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  PivotModule,
  RowGroupingPanelModule,
  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,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  SetFilterModule,
  PivotModule,
  RowGroupingPanelModule,
];

function countryHeaderValueGetter(params: HeaderValueGetterParams) {
  switch (params.location) {
    case "csv":
      return "CSV Country";
    case "columnToolPanel":
      return "TP Country";
    case "columnDrop":
      return "CD Country";
    case "header":
      return "H Country";
    default:
      return "Should never happen!";
  }
}

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

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    {
      field: "athlete",
      minWidth: 200,
      enableRowGroup: true,
      enablePivot: true,
    },
    {
      field: "age",
      enableValue: true,
    },
    {
      field: "country",
      minWidth: 200,
      enableRowGroup: true,
      enablePivot: true,
      headerValueGetter: countryHeaderValueGetter,
    },
    {
      field: "year",
      enableRowGroup: true,
      enablePivot: true,
    },
    {
      field: "date",
      minWidth: 180,
      enableRowGroup: true,
      enablePivot: true,
    },
    {
      field: "sport",
      minWidth: 200,
      enableRowGroup: true,
      enablePivot: true,
    },
    {
      field: "gold",
      hide: true,
      enableValue: true,
      toolPanelClass: "tp-gold",
    },
    {
      field: "silver",
      hide: true,
      enableValue: true,
      toolPanelClass: ["tp-silver"],
    },
    {
      field: "bronze",
      hide: true,
      enableValue: true,
      toolPanelClass: (params) => {
        return "tp-bronze";
      },
    },
    {
      headerName: "Total",
      field: "total",
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
      filter: true,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

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

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            autoGroupColumnDef={autoGroupColumnDef}
            sideBar={"columns"}
            rowGroupPanelShow={"always"}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Tool Panel Styling](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-columns-customising/styling/reactFunctionalTs/)

To add a CSS class to a column in the tool panel, set `toolPanelClass` on its column definition:

```jsx
const [columnDefs, setColumnDefs] = useState([
    // set as string
    { field: 'gold', toolPanelClass: 'tp-gold' },

    // set as array of strings
    { field: 'silver', toolPanelClass: ['tp-silver'] },

    // set as function returning string or array of strings
    {
        field: 'bronze',
        toolPanelClass: params => {
            return 'tp-bronze';
        },
    }
]);

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

## Naming Columns

To give a column a different name in the tool panel, use a [`headerValueGetter`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-headers/#header-value-getters) and return the name when `params.location` is `'columnToolPanel'`:

```jsx
const [columnDefs, setColumnDefs] = useState([
    {
        field: 'country',
        headerValueGetter: params => params.location === 'columnToolPanel' ? 'Country (TP)' : 'Country',
    }
]);

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

In the [example above](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-customising/#styling-columns), the country column uses a `headerValueGetter` to show a different name in the tool panel, the drop zones and the grid header. Drag it into the Row Groups section to see the drop zone name.

## Custom Label Renderers

Use `columnLabelRenderer` to replace the text shown for columns and column groups in the Columns section. The grid continues to provide and manage the checkbox, drag handle and group expand controls.

Supply the renderer directly, or reference a name registered in the grid's [`components`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/components/#registering-custom-components) map, and pass additional properties through `columnLabelRendererParams`. To use different renderers for different columns or column groups, use `columnLabelRendererSelector` instead.

```jsx
const components = {
    customColumnLabel: CustomColumnLabel,
};
const sideBar = useMemo(() => { 
	return {
        toolPanels: [{
            id: 'columns',
            labelDefault: 'Columns',
            labelKey: 'columns',
            iconKey: 'columns',
            toolPanel: 'agColumnsToolPanel',
            toolPanelParams: {
                columnLabelRenderer: 'customColumnLabel',
                columnLabelRendererParams: {
                    columnIcon: '●',
                    columnGroupIcon: '◆',
                },
            },
        }],
    };
}, []);

<AgGridReact
    components={components}
    sideBar={sideBar}
/>
```

The renderer receives either `column` or `columnGroup`, together with the resolved `displayName` and a `source` of `'columnsToolPanel'`. The same renderer can be configured independently for the [Column Chooser](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-chooser/#custom-label-renderers).

#### Custom Label Renderers

```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,
  Components,
  GridOptions,
  ModuleRegistry,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import { ColumnsToolPanelModule } from "ag-grid-enterprise";
import "./styles.css";
import CustomColumnLabel from "./customColumnLabel.tsx";

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

const modules = [ClientSideRowModelModule, ColumnsToolPanelModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    {
      athlete: "Michael Phelps",
      country: "United States",
      sport: "Swimming",
      gold: 8,
      silver: 0,
      bronze: 0,
    },
  ]);
  const [columnDefs, setColumnDefs] = useState<(ColDef | ColGroupDef)[]>([
    {
      headerName: "Athlete Details",
      groupId: "athleteDetails",
      children: [
        { field: "athlete" },
        { field: "country" },
        { field: "sport" },
      ],
    },
    {
      headerName: "Results",
      groupId: "results",
      children: [{ field: "gold" }, { field: "silver" }, { field: "bronze" }],
    },
  ]);
  const components = useMemo<Components>(() => {
    return {
      customColumnLabel: CustomColumnLabel,
    };
  }, []);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 120,
    };
  }, []);
  const sideBar = useMemo<
    SideBarDef | string | string[] | boolean | null
  >(() => {
    return {
      toolPanels: [
        {
          id: "columns",
          labelDefault: "Columns",
          labelKey: "columns",
          iconKey: "columns",
          toolPanel: "agColumnsToolPanel",
          toolPanelParams: {
            columnLabelRenderer: "customColumnLabel",
            columnLabelRendererParams: {
              columnIcon: "●",
              columnGroupIcon: "◆",
            },
          },
        },
      ],
      defaultToolPanel: "columns",
    };
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div style={gridStyle}>
            <AgGridReact
              rowData={rowData}
              columnDefs={columnDefs}
              components={components}
              defaultColDef={defaultColDef}
              sideBar={sideBar}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Custom Label Renderers](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-columns-customising/custom-column-labels/reactFunctionalTs/)

> **Note**
>
> Column search, tooltips, drag labels and accessibility announcements continue to use `displayName`, rather than text extracted from the renderer. Column selection rows have a fixed height, so renderer content should remain inline and fit within the configured list item height. Clicking the rendered label retains the normal selection behaviour; interactive elements should stop event propagation when they should not toggle the column.

## Expand / Collapse Column Groups

Call `expandColumnGroups()` and `collapseColumnGroups()` on the [Columns Tool Panel instance](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-configuration/#columns-tool-panel-instance) to expand or collapse all of its column groups, or pass `groupId`s to target individual groups; see [Expand / Collapse API](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-customising/#expand--collapse-api). To start with all column groups collapsed, set `contractColumnSelection` in `toolPanelParams` instead.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `contractColumnSelection` | `boolean` |  |  | By default, column groups start expanded. Pass `true` to start with groups collapsed. |

In the example below, `onGridReady` collapses all column groups in the tool panel. Use the buttons to try each call from the [Expand / Collapse API](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-customising/#expand--collapse-api).

#### Expand / Collapse Column Groups

```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 {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  SideBarDef,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  PivotModule,
  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,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  SetFilterModule,
  PivotModule,
  TextFilterModule,
];

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 | ColGroupDef)[]>([
    {
      groupId: "athleteGroupId",
      headerName: "Athlete",
      children: [
        {
          headerName: "Name",
          field: "athlete",
          minWidth: 200,
          filter: "agTextColumnFilter",
        },
        {
          groupId: "competitionGroupId",
          headerName: "Competition",
          children: [{ field: "year" }, { field: "date", minWidth: 180 }],
        },
      ],
    },
    {
      groupId: "medalsGroupId",
      headerName: "Medals",
      children: [
        { field: "gold" },
        { field: "silver" },
        { field: "bronze" },
        { field: "total" },
      ],
    },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 100,
      // allow every column to be aggregated
      enableValue: true,
      // allow every column to be grouped
      enableRowGroup: true,
      // allow every column to be pivoted
      enablePivot: true,
      filter: true,
    };
  }, []);
  const autoGroupColumnDef = useMemo<AutoGroupColumnDef>(() => {
    return {
      minWidth: 200,
    };
  }, []);

  const onGridReady = useCallback((params: GridReadyEvent) => {
    const columnsToolPanel = params.api.getToolPanelInstance("columns")!;
    columnsToolPanel.collapseColumnGroups();
  }, []);
  const { data, loading } = useFetchJson<IOlympicData>(
    "https://www.ag-grid.com/example-assets/olympic-winners.json",
  );

  const expandAllGroups = useCallback(() => {
    const columnsToolPanel =
      gridRef.current!.api.getToolPanelInstance("columns")!;
    columnsToolPanel.expandColumnGroups();
  }, []);

  const collapseAllGroups = useCallback(() => {
    const columnsToolPanel =
      gridRef.current!.api.getToolPanelInstance("columns")!;
    columnsToolPanel.collapseColumnGroups();
  }, []);

  const expandAthleteAndCompetitionGroups = useCallback(() => {
    const columnsToolPanel =
      gridRef.current!.api.getToolPanelInstance("columns")!;
    columnsToolPanel.expandColumnGroups([
      "athleteGroupId",
      "competitionGroupId",
    ]);
  }, []);

  const collapseCompetitionGroups = useCallback(() => {
    const columnsToolPanel =
      gridRef.current!.api.getToolPanelInstance("columns")!;
    columnsToolPanel.collapseColumnGroups(["competitionGroupId"]);
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div>
            <span className="button-group">
              <button onClick={expandAllGroups}>Expand All</button>
              <button onClick={collapseAllGroups}>Collapse All</button>
              <button onClick={expandAthleteAndCompetitionGroups}>
                Expand Athlete &amp; Competition
              </button>
              <button onClick={collapseCompetitionGroups}>
                Collapse Competition
              </button>
            </span>
          </div>

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

              rowData={data}
              loading={loading}
              columnDefs={columnDefs}
              defaultColDef={defaultColDef}
              autoGroupColumnDef={autoGroupColumnDef}
              sideBar={"columns"}
              onGridReady={onGridReady}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Expand / Collapse Column Groups](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-columns-customising/expand-collapse/reactFunctionalTs/)

> **Note**
>
> The expanded column groups are saved and restored as part of [Grid State](https://www.ag-grid.com/archive/36.3.0/react-data-grid/grid-state/).

## Context Menu

Right-clicking or long-pressing a column or column group label opens a menu with items for moving, grouping, aggregating and pivoting. The menu can be customised, including with custom menu items.

### Built-In Menu Items

The following menu items are shown by default based on the column's configuration and the grid's current state:

- `scrollIntoView`: "Scroll *column* into View". Scrolls the column into view. Hidden while pivoting, or when the column is pinned or hidden.
- `rowGroup`: "Group by *column*" or "Un-Group by *column*". Appears only when the column allows row grouping.
- `value`: "Add *column* to values" or "Remove *column* from values". Adds or removes the column as an aggregated value (the **Values** section). Appears only when the column allows aggregation.
- `pivot`: "Add *column* to labels" or "Remove *column* from labels". Adds or removes the column as a pivot column label (the **Column Labels** section). Appears only in pivot mode when the column allows pivoting.
- `moveUp`: "Move Up". Moves the column or group one available position up the list.
- `moveDown`: "Move Down". Moves the column or group one available position down the list.

For a column group, `rowGroup`, `value` and `pivot` apply to every child column that individually allows the action; `scrollIntoView` scrolls only the first visible child column into view.

The move items also appear in the [Column Chooser](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-chooser/). They are hidden in pivot mode but are unaffected by `functionsReadOnly`.

Movement follows [Column Moving](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-moving/) and [tool panel reordering](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-configuration/#suppress-column-reordering) restrictions. In deferred mode, changes wait for **Apply**.

Customise labels using the `moveUp` / `moveDown` [locale keys](https://www.ag-grid.com/archive/36.3.0/react-data-grid/localisation/) and arrows using the `menuMoveUp` / `menuMoveDown` [icon keys](https://www.ag-grid.com/archive/36.3.0/react-data-grid/custom-icons/).

With [Read Only Functions](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-configuration/#read-only-functions), `rowGroup`, `value` and `pivot` are not shown.

### Custom Menu Items

Customise the menu items with `colDef.columnMenuItems` or `getColumnMenuItems()`. See [Column Menu - Customising the menu items](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-menu/#customising-the-menu-items). The callback's `params.source` is `'columnsToolPanel'` when triggered from the Columns Tool Panel.

The example below shows both the built-in items and this customisation. Note the following:

- Right-click **Gold** to see the built-in items plus an optional pinning sub-menu and a custom **Highlight Column** item, added by the `getColumnMenuItems()` callback.
- **Silver** hides the "Scroll Silver into View" item via a `colDef.columnMenuItems` callback. As `colDef.columnMenuItems` takes priority over `getColumnMenuItems()`, Silver doesn't get the Highlight Column item.
- **Bronze** restricts its menu to only "Add Bronze to values" via a static `colDef.columnMenuItems` array, so it doesn't get the Highlight Column item either.
- `colDef.columnMenuItems` applies to every column menu, so the Silver and Bronze changes also apply to their column header menu and Column Chooser menu. Other columns keep their defaults in those menus, as `getColumnMenuItems()` returns `params.defaultItems` for those sources.

#### Customising the Tool Panel Menu

```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 {
  CellStyleModule,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GetColumnMenuItems,
  GridApi,
  GridOptions,
  MenuItemDef,
  ModuleRegistry,
  RowApiModule,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
} from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";

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

const modules = [
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
  CellStyleModule,
  RowApiModule,
];

const highlightedColumns = new Set<string>();

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

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete", minWidth: 200, enableRowGroup: true },
    { field: "age", enableValue: true },
    { field: "country", minWidth: 200, enableRowGroup: true },
    { field: "year", enableRowGroup: true },
    { field: "sport", minWidth: 200, enableRowGroup: true },
    { field: "gold", enableValue: true },
    {
      field: "silver",
      enableValue: true,
      // column-level override: hide the "Scroll into View" item for this column only.
      // colDef.columnMenuItems takes priority over getColumnMenuItems, so silver and
      // bronze don't get the Highlight Column item added below.
      columnMenuItems: (params) =>
        params.defaultItems.filter((item) => item !== "scrollIntoView"),
    },
    // column-level override: only ever show the "Add to values" item
    { field: "bronze", enableValue: true, columnMenuItems: ["value"] },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
      minWidth: 150,
      cellStyle: (params) =>
        highlightedColumns.has(params.column.getColId())
          ? { backgroundColor: "rgba(255, 193, 7, 0.25)" }
          : null,
    };
  }, []);
  const getColumnMenuItems = useCallback((params) => {
    // Customise the Columns Tool Panel menu
    if (params.source === "columnsToolPanel") {
      const colId = params.column?.getColId();
      const highlightColumn: MenuItemDef = {
        name: "Highlight Column",
        checked: colId ? highlightedColumns.has(colId) : false,
        action: () => {
          if (!colId) return;
          if (highlightedColumns.has(colId)) {
            highlightedColumns.delete(colId);
          } else {
            highlightedColumns.add(colId);
          }
          // Redraw rows so cellStyle re-evaluates on fresh cells
          params.api.redrawRows();
        },
      };
      // Append an optional pinning sub-menu and a custom item to the built-in tool panel items
      return [
        ...params.defaultItems,
        "separator",
        "pinSubMenu",
        highlightColumn,
      ];
    }
    // Return default for column header menu and column picker
    return params.defaultItems;
  }, []);

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

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            sideBar={"columns"}
            getColumnMenuItems={getColumnMenuItems}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Customising the Tool Panel Menu](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-columns-customising/customising-tool-panel-menu/reactFunctionalTs/)

### Drop Zone Menus

Move Up and Move Down reorder pills within Row Groups, Values and Column Labels, not grid columns. Horizontal panels use Move Left and Move Right.

Right-click a pill to open its menu. With a pill focused, `⇧ Shift`+`F10` or the context-menu key opens the same menu.

Move items follow drag-and-drop eligibility and [group locking](https://www.ag-grid.com/archive/36.3.0/react-data-grid/grouping-group-panel/#prevent-changes-to-group-order). They are hidden with `functionsReadOnly`, but pivot mode and column-layout restrictions do not block them.

Labels use the `moveUp`, `moveDown`, `moveLeft`, `moveRight` [locale keys](https://www.ag-grid.com/archive/36.3.0/react-data-grid/localisation/); arrows use the `menuMoveUp`, `menuMoveDown`, `menuMoveLeft`, `menuMoveRight` [icon keys](https://www.ag-grid.com/archive/36.3.0/react-data-grid/custom-icons/).

Use `getColumnDropZoneMenuItems` to filter `defaultItems`, add custom items or return `[]` to hide a menu. Its `source` is `'rowGroup'`, `'pivot'` or `'aggregation'`. For example, hide the Values menu and keep the others:

```javascript
const gridOptions = {
    getColumnDropZoneMenuItems: ({ source, defaultItems }) =>
        source === 'aggregation' ? [] : defaultItems,
};
```

Keep the callback free of side effects; it may run before the menu opens. Column-menu callbacks do not configure drop-zone menus.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getColumnDropZoneMenuItems` | `GetColumnDropZoneMenuItems` |  |  | Customise the context menu for pills in Row Group, Pivot and Values drop zones. Return `[]` to hide it. Called when pills are created to determine menu availability for accessibility, and when opening a menu. Independent of `columnMenuItems` and `getColumnMenuItems`. [Modules](https://www.ag-grid.com/archive/36.3.0/react-data-grid/modules/) (any of): `RowGroupingPanelModule`, `ColumnsToolPanelModule`. |

## Custom Drag and Drop Image

The drag and drop image can be customised via the grid properties `dragAndDropImageComponent` and `dragAndDropImageComponentParams`.

#### Custom Drag and Drop Image

```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,
  ModuleRegistry,
  NumberFilterModule,
  SideBarDef,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  FiltersToolPanelModule,
  PivotModule,
  RowGroupingPanelModule,
  SetFilterModule,
} from "ag-grid-enterprise";
import "./styles.css";
import CustomDragAndDropImage from "./customDragAndDropImage.tsx";
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,
  ColumnsToolPanelModule,
  FiltersToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  PivotModule,
  SetFilterModule,
  RowGroupingPanelModule,
];

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

  const [columnDefs, setColumnDefs] = useState<ColDef[]>([
    { field: "athlete" },
    { field: "country" },
    { field: "year", width: 100 },
    { field: "date" },
    { field: "sport" },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
  ]);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      width: 170,
      filter: true,
      // allow every column to be aggregated
      enableValue: true,
      // allow every column to be grouped
      enableRowGroup: true,
      // allow every column to be pivoted
      enablePivot: true,
    };
  }, []);
  const dragAndDropImageComponent = useCallback(CustomDragAndDropImage, []);
  const dragAndDropImageComponentParams = useMemo(() => {
    return {
      accentColour: "SlateGray",
    };
  }, []);

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

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact<IOlympicData>
            rowData={data}
            loading={loading}
            columnDefs={columnDefs}
            defaultColDef={defaultColDef}
            sideBar={true}
            rowGroupPanelShow={"always"}
            dragAndDropImageComponent={dragAndDropImageComponent}
            dragAndDropImageComponentParams={dragAndDropImageComponentParams}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

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

[Live example: Custom Drag and Drop Image](https://www.ag-grid.com/archive/36.3.0/examples/tool-panel-columns-customising/custom-drag-drop-image/reactFunctionalTs/)

```ts
const CustomDragAndDropImage = (props: CustomDragAndDropImageProps) => {
    return <div>{props.label}</div>;
};
```

The following props are passed to the Custom Component (`CustomDragAndDropImageProps` interface).

### CustomDragAndDropImageProps

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `label` | `string` |  |  | The label provided by the grid about the item being dragged. |
| `icon` | `string \| null` |  |  | The name of the icon provided by the grid about the current drop target. |
| `shake` | `boolean` |  |  | `true` if the grid is attempting to scroll horizontally while dragging. |
| `dragSource` | `DragSource` |  |  | DragSource |
| `api` | [`GridApi`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/grid-api/) |  |  | The grid api. |
| `context` | [`TContext`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/typescript-generics/#context-tcontext) |  |  | Application context as set on `gridOptions.context`. |

### Custom Params

On top of the parameters provided by the grid, you can also provide your own parameters. This is useful if you want to allow configuring the component. For example, you might have parts of the grid that you want to highlight with a different colour. The [example above](https://www.ag-grid.com/archive/36.3.0/react-data-grid/tool-panel-columns-customising/#custom-drag-and-drop-image) passes its own parameters through `dragAndDropImageComponentParams`.

```js
const gridOptions = {
    dragAndDropImageComponent: MyDragAndDropImageComponent,
    dragAndDropImageComponentParams : {
        accentColour: 'SlateGray'
    }
}
```

## API

### Custom Label Renderer Parameters

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `columnLabelRenderer` | `any` |  |  | Component used to render column and column group labels. The checkbox, drag handle and expand controls remain grid managed. |
| `columnLabelRendererParams` | `any` |  |  | Additional parameters passed to the `columnLabelRenderer`. |
| `columnLabelRendererSelector` | `ColumnSelectionLabelRendererSelectorFunc` |  |  | Callback to select which renderer to use for an individual column or column group label. The result can also provide renderer-specific `params`. Return `undefined` to use `columnLabelRenderer`. |

The parameters passed to a custom label renderer:

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

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `displayName` | `string \| null` |  |  | The text value resolved from the column or column group definition. |
| `column` | [`Column \| null`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-object/) |  |  | The column being rendered, or `null` when rendering a column group. |
| `columnGroup` | [`ProvidedColumnGroup \| null`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/column-object-group/#reference-ProvidedColumnGroup) |  |  | The column group being rendered, or `null` when rendering a column. |
| `source` | `ColumnSelectionPanelSource` |  |  | The panel in which the label is rendered. |
| `api` | [`GridApi`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/grid-api/) |  |  | The grid api. |
| `context` | [`TContext`](https://www.ag-grid.com/archive/36.3.0/react-data-grid/typescript-generics/#context-tcontext) |  |  | Application context as set on `gridOptions.context`. |

### Expand / Collapse API

```jsx
const columnsToolPanel = gridApi.getToolPanelInstance('columns');

// expands all column groups in the Columns Tool Panel
columnsToolPanel.expandColumnGroups();

// collapses all column groups in the Columns Tool Panel
columnsToolPanel.collapseColumnGroups();

// expands the 'Athlete' and 'Competition' column groups in the Columns Tool Panel
columnsToolPanel.expandColumnGroups(['athleteGroupId', 'competitionGroupId']);

// collapses the 'Competition' column group in the Columns Tool Panel
columnsToolPanel.collapseColumnGroups(['competitionGroupId']);
```

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `expandColumnGroups` | `Function` |  |  | Expands the column groups with the supplied `groupIds`, or all column groups if not supplied. |
| `collapseColumnGroups` | `Function` |  |  | Collapses the column groups with the supplied `groupIds`, or all column groups if not supplied. |
