---
product: "AG Grid"
title: "Column Menu"
description: "The Column Menu is launched from a column header and provides actions such as sorting, pinning and sizing columns. Its item opens the separate , while enabled column filters can be opened from the menu or the header filter button."
enterprise: true
framework: angular
version: "36.2.0"
related:
    - title: "Tool Panels"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/tool-panel/"
    - title: "Quick Access Toolbar"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/toolbar/"
    - title: "Column Chooser"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-chooser/"
    - title: "Context Menu"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/context-menu/"
    - title: "Menu Item Component"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/component-menu-item/"
    - title: "Status Bar"
      url: "https://www.ag-grid.com/archive/36.2.0/angular-data-grid/status-bar/"
llms: "https://www.ag-grid.com/archive/36.2.0/llms.txt"
---

# Column Menu

The Column Menu is launched from a column header and provides actions such as sorting, pinning and sizing columns. Its **Choose Columns** item opens the separate [Column Chooser](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-chooser/), while enabled column filters can be opened from the menu or the header filter button.

> **Note**
>
> AG Grid Community does not have a menu, but can launch [Column Filters](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/filtering/) if enabled (see [Launching Filters](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/filter-api/#launching-filters) for configuration details).

The following example shows the column menu:

- The **Athlete** column does not have filtering enabled, and only shows the main menu.
- The **Age** column has filtering enabled, and shows an additional filter icon. Open and apply a filter to see the behaviour.
- The **Country** column has filtering enabled with the floating filter. Open and apply a filter to see the behaviour.
- Right-clicking on the column headers will also display the column menu.
- Right-clicking in the empty space to the right of the column headers will display the column menu with options to choose/reset the columns.

#### Column Menu

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  CalculatedColumnsGridOption,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnAutoSizeModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  CalculatedColumnsModule,
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
} from "ag-grid-enterprise";

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

ModuleRegistry.registerModules([
  CalculatedColumnsModule,
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  ColumnAutoSizeModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [columnDefs]="columnDefs"
    [defaultColDef]="defaultColDef"
    [calculatedColumns]="true"
    [rowData]="rowData"
    (gridReady)="onGridReady($event)"
  /> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    { field: "athlete", minWidth: 200 },
    { field: "age", filter: true },
    { field: "country", filter: true, floatingFilter: true, minWidth: 200 },
  ];
  defaultColDef: ColDef = {
    minWidth: 100,
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<
        IOlympicData[]
      >("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Column Menu](https://www.ag-grid.com/archive/36.2.0/examples/column-menu/column-menu/angular/)

## Customising the Column Menu

How the column menu is launched from the header can be configured via the following column definition properties.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `suppressHeaderMenuButton` | `boolean` |  |  |  |
| `suppressHeaderFilterButton` | `boolean` |  |  |  |
| `suppressHeaderContextMenu` | `boolean` |  |  |  |

The following example demonstrates different ways of customising the column menu:

- The **Athlete** column has a filter and the menu button suppressed, but still available via right-click.
- The **Age** column has a floating filter and the menu suppressed, but still available via right-click.
- The **Country** column has a filter and the header filter button suppressed.
- The **Year** column has a floating filter and the header filter button suppressed.
- The **Sport** column has no filter and the menu suppressed on right-click.
- The **Gold** column has no filter and the menu button suppressed, but still available via right-click
- The **Silver** column has a filter (with the header filter button suppressed), and the menu button suppressed but still available via right-click.
- The **Bronze** column has a floating filter and the menu button suppressed, but still available via right-click.
- The **Total** column has the menu button, header filter button and right-click menu suppressed.

#### Customising the Column Menu

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  CalculatedColumnsGridOption,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  CalculatedColumnsModule,
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
} from "ag-grid-enterprise";

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

ModuleRegistry.registerModules([
  CalculatedColumnsModule,
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [columnDefs]="columnDefs"
    [defaultColDef]="defaultColDef"
    [calculatedColumns]="true"
    [rowData]="rowData"
    (gridReady)="onGridReady($event)"
  /> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    {
      field: "athlete",
      minWidth: 200,
      filter: true,
      suppressHeaderMenuButton: true,
    },
    {
      field: "age",
      filter: true,
      floatingFilter: true,
      suppressHeaderMenuButton: true,
    },
    {
      field: "country",
      minWidth: 200,
      filter: true,
      suppressHeaderFilterButton: true,
    },
    {
      field: "year",
      filter: true,
      floatingFilter: true,
      suppressHeaderFilterButton: true,
    },
    { field: "sport", minWidth: 200, suppressHeaderContextMenu: true },
    {
      field: "gold",
      suppressHeaderMenuButton: true,
      suppressHeaderFilterButton: true,
    },
    {
      field: "silver",
      filter: true,
      suppressHeaderMenuButton: true,
      suppressHeaderFilterButton: true,
    },
    {
      field: "bronze",
      filter: true,
      floatingFilter: true,
      suppressHeaderMenuButton: true,
      suppressHeaderFilterButton: true,
    },
    {
      field: "total",
      filter: true,
      suppressHeaderMenuButton: true,
      suppressHeaderFilterButton: true,
      suppressHeaderContextMenu: true,
    },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 100,
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<
        IOlympicData[]
      >("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Customising the Column Menu](https://www.ag-grid.com/archive/36.2.0/examples/column-menu/customising-column-menu/angular/)

## Customising the Menu Items

The menu shows a default set of items. You can add your own items, or change which defaults are shown, via two independent properties - use whichever suits, or both:

- `colDef.columnMenuItems` - set per column. Either a list of menu items, or a callback which is passed the list of default items.
- `getColumnMenuItems()` - a grid option callback which is passed the list of default items, the column, and the `source` of the menu.

When both are set, `colDef.columnMenuItems` takes priority over `getColumnMenuItems()`.

The `source` param is one of `'columnMenu'`, `'columnsToolPanel'` or `'columnChooser'`, so a single callback can tailor the items for the column menu, the [Columns Tool Panel](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/tool-panel-columns/#context-menu) context menu, and the [Column Chooser](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-chooser/).

Each item is either a string or a `MenuItemDef`. Use a string to pick a built-in item and a `MenuItemDef` for your own. All built-in tokens share one type, `DefaultColumnMenuItem`, and each is shown only where it applies to the column and grid state. The column menu's [built-in items](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-menu/#built-in-menu-items) are listed below.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `columnMenuItems` | `(DefaultColumnMenuItem \| MenuItemDef)[] \| GetColumnMenuItems` |  |  |  |

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getColumnMenuItems` | `GetColumnMenuItems` |  |  |  |

### Legacy Column Menu Properties

`colDef.mainMenuItems` and the grid option `getMainMenuItems()` are the original way to customise the menu. They behave the same way, but apply to the column menu only - not the Columns Tool Panel or Column Chooser - and their callbacks do not receive a `source`. Prefer `columnMenuItems` / `getColumnMenuItems()`; these older properties remain supported and take effect when the newer ones are not set.

The full order of precedence is `colDef.columnMenuItems`, then `getColumnMenuItems()`, then `colDef.mainMenuItems`, then `getMainMenuItems()`. A grid-level `getColumnMenuItems()` therefore takes precedence over a per-column `mainMenuItems`.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `mainMenuItems` | `(DefaultMenuItem \| MenuItemDef)[] \| GetMainMenuItems` |  |  |  |

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `getMainMenuItems` | `GetMainMenuItems` |  |  |  |

### Built-In Menu Items

The following is a list of all the default built-in menu items with the rules about when they are shown.

- `sortAscending`: Sort the column in ascending order. Not included in the default items when `columnMenu = 'legacy'`, or when the column is already sorted in ascending order.
- `sortDescending`: Sort the column in descending order. Not included in the default items when `columnMenu = 'legacy'`, or when the column is already sorted in descending order.
- `sortAbsoluteAscending`: Sort the column in ascending order by magnitude, ignoring the sign - see [Absolute Sorting](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/row-sorting/#absolute-sorting). Not included in the default items when `columnMenu = 'legacy'`, when the column does not allow absolute sorting, or when the column is already sorted in absolute ascending order.
- `sortAbsoluteDescending`: Sort the column in descending order by magnitude, ignoring the sign - see [Absolute Sorting](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/row-sorting/#absolute-sorting). Not included in the default items when `columnMenu = 'legacy'`, when the column does not allow absolute sorting, or when the column is already sorted in absolute descending order.
- `sortUnSort`: Clear the sort on the column. Not included in the default items when `columnMenu = 'legacy'`, or when the column is not sorted.
- `calculatedColumn`: Show the Calculated Columns options. If the column selected is a Calculated Column, the menu will show options to edit and remove the column.
- `editColumnName`: Rename the column header. Only shown when `headerNameEditable` is set on the column, and never on a calculated column, which is renamed via its **Edit Calculated Column** dialog instead.
- `columnFilter`: Show the column filter. Not included in the default items when `columnMenu = 'legacy'`, a filter is not enabled, or the header filter button or floating filter button are displayed.
- `columnChooser`: Show the [Column Chooser](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-chooser/). Not included in the default items when `columnMenu = 'legacy'`.
- `pinSubMenu`: Sub-menu for pinning. Always shown.
- `valueAggSubMenu`: Sub-menu for value aggregation. Always shown.
- `autoSizeThis`: Auto-size the current column. Always shown.
- `autoSizeAll`: Auto-size all columns. Always shown.
- `rowGroup`: Group by this column. Only shown if column is not grouped. Note this will appear once there is row grouping.
- `rowUnGroup`: Un-group by this column. Only shown if column is grouped. Note this will appear once there is row grouping.
- `resetColumns`: Reset column details. Always shown.
- `expandAll`: Expand all groups. Only shown if grouping by at least one column.
- `contractAll`: Collapse all groups. Only shown if grouping by at least one column.

The `defaultItems` list will change on different calls, depending on, for example, which columns are currently used for grouping.

If you do not override the list of menu items, then the items displayed will be based on the rules above.

The `columnMenu = 'legacy'` rules above apply to the default items only. A token supplied explicitly through `columnMenuItems`, `getColumnMenuItems()`, `mainMenuItems` or `getMainMenuItems()` is still rendered under the legacy menu.

[Columns Tool Panel](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/tool-panel-columns/#context-menu) tokens such as `value` can also be returned here, and are shown where they apply to the column.

### Menu Item Separators

Menu items can be grouped together by adding separators between groups. Separators are defined by the string value `'separator'`. For example, you could add menu item separators as follows:

```js
menuItems.push('separator')
```

### Custom Menu Item Components

In addition to the provided menu items, it is also possible to create custom menu item components.

For more details, refer to the section: [Custom Menu Item Components](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/component-menu-item/).

### Example: Customising the Menu Items

The following example demonstrates the `colDef.columnMenuItems` property:

- The **Athlete** column shows the list of built-in items.
- The **Age** column includes the `value` token before its custom items. The grid is grouped by **Sport**, so **Add Age to values** aggregates Age in the group rows.
- The **Country** column provides two custom items and one built-in item, **Reset Columns** (`resetColumns`). Clicking a custom item logs to the developer console.
- The **Year** column keeps the default items but removes the separators, the pinning sub-menu, and the value aggregation sub-menu.

#### Customising the Menu Items

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  AutoGroupColumnDef,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  DefaultColumnMenuItem,
  GetColumnMenuItemsParams,
  GridApi,
  GridOptions,
  GridReadyEvent,
  MenuItemDef,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
  RowGroupingModule,
} from "ag-grid-enterprise";

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

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  RowGroupingModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [columnDefs]="columnDefs"
    [autoGroupColumnDef]="autoGroupColumnDef"
    [defaultColDef]="defaultColDef"
    [rowData]="rowData"
    (gridReady)="onGridReady($event)"
  /> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    { field: "athlete", minWidth: 200 },
    {
      field: "age",
      enableValue: true,
      minWidth: 150,
      columnMenuItems: (params: GetColumnMenuItemsParams) => {
        // 'value' is a Columns Tool Panel token; it resolves on the column menu too.
        const menuItems: (DefaultColumnMenuItem | MenuItemDef)[] = [
          "value",
          "separator",
          ...params.defaultItems,
          {
            name: "A Custom Item",
            action: () => {
              console.log("A Custom Item selected");
            },
          },
          {
            name: "Custom Sub Menu",
            subMenu: [
              {
                name: "Black",
                action: () => {
                  console.log("Black was pressed");
                },
              },
              {
                name: "White",
                action: () => {
                  console.log("White was pressed");
                },
              },
              {
                name: "Grey",
                action: () => {
                  console.log("Grey was pressed");
                },
              },
            ],
          },
        ];
        return menuItems;
      },
    },
    {
      field: "country",
      minWidth: 200,
      columnMenuItems: [
        {
          // our own item with an icon
          name: "A Custom Item",
          action: () => {
            console.log("A Custom Item selected");
          },
          icon: '<img src="https://www.ag-grid.com/example-assets/lab.png" style="width: 14px;" />',
        },
        {
          // our own icon with a check box
          name: "Another Custom Item",
          action: () => {
            console.log("Another Custom Item selected");
          },
          checked: true,
        },
        "resetColumns", // a built in item
      ],
    },
    {
      field: "year",
      columnMenuItems: (params: GetColumnMenuItemsParams) => {
        const menuItems: (DefaultColumnMenuItem | MenuItemDef)[] = [];
        const itemsToExclude = ["separator", "pinSubMenu", "valueAggSubMenu"];
        params.defaultItems.forEach((item) => {
          if (itemsToExclude.indexOf(item) < 0) {
            menuItems.push(item);
          }
        });
        return menuItems;
      },
    },
    { field: "sport", minWidth: 200, rowGroup: true, enableRowGroup: true },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  autoGroupColumnDef: AutoGroupColumnDef = {
    minWidth: 330,
  };
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 100,
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<
        IOlympicData[]
      >("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Customising the Menu Items](https://www.ag-grid.com/archive/36.2.0/examples/column-menu/customising-menu-items/angular/)

## Column Chooser

Selecting **Choose Columns** from the column menu opens the Column Chooser, which allows users to show, hide and reorder columns. See [Column Chooser](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-chooser/) for configuration, custom labels, layouts and API usage.

## Column Menu API / Events

The `gridApi` has the following methods that can be used to interact with the column menu:

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `showColumnMenu` | `Function` |  |  |  |
| `hidePopupMenu` | `Function` |  |  |  |

Column filters are not considered part of the menu, so have their own API methods to show/hide.

However, when using the [Legacy Tabbed Column Menu](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/column-menu/#legacy-tabbed-column-menu), the filter popup is part of the column menu, and can be opened/closed via the column menu API methods.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `showColumnFilter` | `Function` |  |  |  |
| `hideColumnFilter` | `Function` |  |  |  |

The following column menu event is emitted by the grid. Note that this also includes the column filter popup.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `columnMenuVisibleChanged` | `ColumnMenuVisibleChangedEvent` |  |  |  |

The following example demonstrates the column menu API and events (by clicking the buttons outside the grid).

Note that the column menu and column filter popup close automatically when clicking outside the grid, so there are no buttons to close them in the example.

#### Column Menu API

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import "./styles.css";
import {
  CalculatedColumnsGridOption,
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnMenuVisibleChangedEvent,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  CalculatedColumnsModule,
  ColumnMenuModule,
  ContextMenuModule,
} from "ag-grid-enterprise";

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

ModuleRegistry.registerModules([
  CalculatedColumnsModule,
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
  ColumnMenuModule,
  ContextMenuModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <div>
      <div class="button-group">
        <button (click)="showColumnFilter('age')">Show Age Filter</button>
        <button (click)="showColumnMenu('age')">Show Age Column Menu</button>
      </div>
    </div>

    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [columnDefs]="columnDefs"
      [defaultColDef]="defaultColDef"
      [calculatedColumns]="true"
      [rowData]="rowData"
      (columnMenuVisibleChanged)="onColumnMenuVisibleChanged($event)"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi<IOlympicData>;

  columnDefs: ColDef[] = [
    { field: "athlete", minWidth: 200 },
    { field: "age" },
    { field: "country", minWidth: 200 },
    { field: "year" },
    { field: "sport", minWidth: 200 },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 100,
    filter: true,
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onColumnMenuVisibleChanged(event: ColumnMenuVisibleChangedEvent) {
    console.log("columnMenuVisibleChanged", event);
  }

  showColumnFilter(colKey: string) {
    this.gridApi.showColumnFilter(colKey);
  }

  showColumnMenu(colKey: string) {
    this.gridApi.showColumnMenu(colKey);
  }

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.gridApi = params.api;

    this.http
      .get<
        IOlympicData[]
      >("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Column Menu API](https://www.ag-grid.com/archive/36.2.0/examples/column-menu/column-menu-api/angular/)

## Menu Popup

The column menu is displayed inside a popup, which can be further configured.

### Repositioning the Popup

If not happy with the position of the popup, you can override its position using the `postProcessPopup(params)` callback. This gives you the popup HTML element so you can change its position should you wish to.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `postProcessPopup` | `PostProcessPopup` |  |  |  |

The following example demonstrates using `postProcessPopup()` to move the **Age** column menu down by 25 pixels.

#### Column Menu Popup

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  PostProcessPopup,
  PostProcessPopupParams,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
} from "ag-grid-enterprise";

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

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [columnDefs]="columnDefs"
    [defaultColDef]="defaultColDef"
    [postProcessPopup]="postProcessPopup"
    [rowData]="rowData"
    (gridReady)="onGridReady($event)"
  /> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    { field: "athlete", minWidth: 200 },
    { field: "age" },
    { field: "country", minWidth: 200 },
    { field: "year" },
    { field: "sport", minWidth: 200 },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 100,
  };
  postProcessPopup: PostProcessPopup = (params: PostProcessPopupParams) => {
    // check callback is for menu
    if (params.type !== "columnMenu") {
      return;
    }
    const columnId = params.column ? params.column.getId() : undefined;
    if (columnId === "age") {
      const ePopup = params.ePopup;
      let oldTopStr = ePopup.style.top!;
      // remove 'px' from the string (AG Grid uses px positioning)
      oldTopStr = oldTopStr.substring(0, oldTopStr.indexOf("px"));
      const oldTop = parseInt(oldTopStr);
      const newTop = oldTop + 25;
      ePopup.style.top = newTop + "px";
    }
  };
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<
        IOlympicData[]
      >("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Column Menu Popup](https://www.ag-grid.com/archive/36.2.0/examples/column-menu/column-menu-popup/angular/)

### Popup Parent

Under most scenarios, the menu will fit inside the grid. However if the grid is small and / or the menu is very large, then the menu will not fit inside the grid and it will be clipped. This will lead to a bad user experience.

To fix this, you should set the [Popup Parent](https://www.ag-grid.com/archive/36.2.0/angular-data-grid/context-menu/#popup-parent) property.

## Legacy Tabbed Column Menu

The menu can also be displayed in the legacy tabbed format with three panels by setting the grid option `columnMenu = 'legacy'`. If you want to change the order in which panels are shown, or hide them, you can specify the property `menuTabs` in the `colDef`.

The property `menuTabs` is an array of strings. The valid values are: `'filterMenuTab'`, `'generalMenuTab'` and `'columnsMenuTab'`.

- `generalMenuTab`: Include to show the main panel.
- `filterMenuTab`: Include to show the filter panel.
- `columnsMenuTab`: Include to show the column chooser panel.

The order of the menu tabs shown in the menu will match the order you specify in this array.

If you don't specify a `menuTabs` for a `colDef` the default is: `['generalMenuTab', 'filterMenuTab', 'columnsMenuTab']`

The following example demonstrates the default tabbed menu:

- The **Athlete** column shows the default tabs.
- The **Age** column changes the order of the tabs to `['filterMenuTab', 'generalMenuTab', 'columnsMenuTab']`
- The **Country** column changes the order of the tabs to `['filterMenuTab', 'columnsMenuTab']`. Note that the `'generalMenuTab'` is suppressed.
- The **Year** column changes the tabs to `['generalMenuTab']`. Note that the `'filterMenuTab'` and `'columnsMenuTab'` are suppressed.
- The **Sport** column hides the menu by suppressing all the menuTabs that can be shown: `[]`.

#### Column Menu

```ts
import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { AgGridAngular } from "ag-grid-angular";
import {
  ClientSideRowModelModule,
  ColDef,
  ColGroupDef,
  ColumnAutoSizeModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  TextFilterModule,
  enableDevValidations,
} from "ag-grid-community";
import {
  ColumnMenuModule,
  ColumnsToolPanelModule,
  ContextMenuModule,
} from "ag-grid-enterprise";

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

ModuleRegistry.registerModules([
  TextFilterModule,
  NumberFilterModule,
  ClientSideRowModelModule,
  ColumnsToolPanelModule,
  ColumnMenuModule,
  ContextMenuModule,
  ColumnAutoSizeModule,
]);
import { IOlympicData } from "./interfaces";

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [columnDefs]="columnDefs"
    [defaultColDef]="defaultColDef"
    [columnMenu]="columnMenu"
    [rowData]="rowData"
    (gridReady)="onGridReady($event)"
  /> `,
})
export class AppComponent {
  columnDefs: ColDef[] = [
    { field: "athlete", minWidth: 200 },
    {
      field: "age",
      menuTabs: ["filterMenuTab", "generalMenuTab", "columnsMenuTab"],
    },
    {
      field: "country",
      minWidth: 200,
      menuTabs: ["filterMenuTab", "columnsMenuTab"],
    },
    { field: "year", menuTabs: ["generalMenuTab"] },
    { field: "sport", minWidth: 200, menuTabs: [] },
    { field: "gold" },
    { field: "silver" },
    { field: "bronze" },
    { field: "total" },
  ];
  defaultColDef: ColDef = {
    flex: 1,
    minWidth: 100,
    filter: true,
  };
  columnMenu: "legacy" | "new" = "legacy";
  rowData!: IOlympicData[];

  constructor(private http: HttpClient) {}

  onGridReady(params: GridReadyEvent<IOlympicData>) {
    this.http
      .get<
        IOlympicData[]
      >("https://www.ag-grid.com/example-assets/olympic-winners.json")
      .subscribe((data) => (this.rowData = data));
  }
}
```

[Live example: Column Menu](https://www.ag-grid.com/archive/36.2.0/examples/column-menu/column-menu-legacy/angular/)

With the legacy menu, the column menu button is hidden until moused over. This can be changed to always show the button using the grid option `suppressMenuHide`.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `suppressMenuHide` | `boolean` |  |  |  |
