# Column Menus

> Columns have menus that allow quick actions - the menus can be customized or hidden altogether.

Canonical page: https://infinite-table.com/docs/learn/columns/column-menus

All columns in the Infinite Table have a default menu, which can be customized or hidden altogether.

## Customise the menu items

To customize the column menu (for all columns, or for a specific column), use the [`getColumnMenuItems`](https://infinite-table.com/docs/reference/infinite-table-props.md#getColumnMenuItems) prop. This function is called with an array of menu items (which are the default items) and it should the final array of menu items - so you can return the default items as is, or you can adjust the default items to fit your needs.

```tsx title="Customizing-column-menu"
function getColumnMenuItems(items, { column }) {
  if (column.id === 'firstName') {
    // you can adjust the default items for a specific column
    items.splice(0, 0, {
      key: 'firstName',
      label: 'First name menu item',
      onClick: () => {
        console.log('Hey there!');
      },
    });
  }

  // or for all columns
  items.push({
    key: 'hello',
    label: 'Hello World',
    onClick: () => {
      alert('Hello World from column ' + column.id);
    },
  });
  return items;
}
```

[`getColumnMenuItems`](https://infinite-table.com/docs/reference/infinite-table-props.md#getColumnMenuItems) can return an empty array, in which case, the column menu will not be shown - however, people will still be able to click the menu icon to trigger the column context menu.

If you want to dynamically decide whether a column should show a menu or not, you can use the [`columns.renderMenuIcon`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.renderMenuIcon) prop.

**Example: Custom column menu items and custom menu icon**

In this example, the currency and preferredLanguage columns have a custom icon for triggering the column context menu.

In addition, the `preferredLanguage` column has a custom header that shows a button for triggering the column context menu.

```tsx
import {
  InfiniteTable,
  DataSource,
  InfiniteTablePropColumns,
} from '@infinite-table/infinite-react';

import * as React from 'react';

type Developer = {
  id: number;
  firstName: string;
  lastName: string;
  country: string;
  city: string;
  currency: string;
  preferredLanguage: string;
  stack: string;
  canDesign: 'yes' | 'no';
  hobby: string;
  salary: number;
  age: number;
};

const dataSource = () => {
  return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k')
    .then((r) => r.json())
    .then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
  currency: {
    field: 'currency',

    // custom menu icon
    renderMenuIcon: () => <div>🌎</div>,
  },

  preferredLanguage: {
    field: 'preferredLanguage',
    defaultWidth: 350,
    header: ({ columnApi, renderLocation }) => {
      // if we're inside the column menu with all columns, return only the col name
      if (renderLocation === 'column-menu') {
        return 'Preferred Language';
      }

      // but for the real column header
      // return this custom content
      return (
        <>
          Preferred Language{' '}
          <button
            // we need to stop propagation so we don't trigger a sort when this button is clicked
            onPointerDown={(e) => e.stopPropagation()}
            onMouseDown={(e) => {
              // again, stop propagation so the menu is not closed automatically
              // so we can control it in the line below
              e.stopPropagation();

              columnApi.toggleContextMenu(e.target);
            }}
            style={{ border: '1px solid magenta', margin: 2 }}
          >
            Toggle menu
          </button>
        </>
      );
    },

    // custom menu icon
    renderMenuIcon: () => <div>🌎</div>,
  },
  salary: {
    field: 'salary',
    // hide the menu icon
    renderMenuIcon: false,
  },
  country: {
    field: 'country',
  },
  id: { field: 'id', defaultWidth: 80, renderMenuIcon: false },
  firstName: {
    field: 'firstName',
  },
};

export default function ColumnContextMenuItems() {
  return (
    <>
      <DataSource<Developer> primaryKey="id" data={dataSource}>
        <InfiniteTable<Developer>
          debugId="getColumnMenuItems-example"
          columnHeaderHeight={70}
          columns={columns}
          getColumnMenuItems={(items, { column }) => {
            if (column.id === 'firstName') {
              // you can adjust the default items for a specific column
              items.splice(0, 0, {
                key: 'firstName',
                label: 'First name menu item',
                onAction: () => {
                  console.log('Hey there!');
                },
              });
            }

            items.push(
              {
                key: 'hello',
                label: 'Hello World',
                onAction: () => {
                  alert('Hello World from column ' + column.id);
                },
              },
              {
                key: 'translate',
                label: 'Translate',
                menu: {
                  items: [
                    {
                      key: 'translateToEnglish',
                      label: 'English',
                      onAction: () => {
                        console.log('Translate to English');
                      },
                    },
                    {
                      key: 'translateToFrench',
                      label: 'French',
                      onAction: () => {
                        console.log('Translate to French');
                      },
                    },
                  ],
                },
              },
            );
            return items;
          }}
        />
      </DataSource>
    </>
  );
}
```

As you can see in the demo above, you can use [`getColumnMenuItems`](https://infinite-table.com/docs/reference/infinite-table-props.md#getColumnMenuItems) to return the default items (received as the first parameter to the function), or another totally different array. We chose to pass the default items to the function, so you can use them as a starting point and adjust them to your needs.

Each item in the array you return from [`getColumnMenuItems`](https://infinite-table.com/docs/reference/infinite-table-props.md#getColumnMenuItems) should have a `key` and a `label` property. Additionally, you can specify an `onAction` function, which will be called when the user clicks the menu item.

It's also possible to create items with submenus. For this, specify a `menu` property in the item, with an `items` array. Each item in the `items` array should have a `key` and a `label` property, as you would expect.

```tsx {8} title="Menu_items_with_submenus"
function getColumnMenuItems(items, { column }) {
  const items = [
    {
      key: 'translate',
      label: 'Translate',
      menu: {
        items: [
          {
            key: 'translateToEnglish',
            label: 'English',
            onAction: () => {
              console.log('Translate to English');
            },
          },
          {
            key: 'translateToFrench',
            label: 'French',
            onAction: () => {
              console.log('Translate to French');
            },
          },
        ],
      },
    },
  ];

  return items;
}
```

## Custom menu icon

To customize the menu icon, use the [`columns.renderMenuIcon`](https://infinite-table.com/docs/reference/infinite-table-props.md#columns.renderMenuIcon) prop. This prop can be a boolean or a function that returns a `ReactNode`.

```tsx title="custom-menu-icon"
const columns = {
  name: {
    field: 'firstName',
    renderMenuIcon: () => <div>🌎</div>,
  },
  salary: {
    field: 'salary',
    renderMenuIcon: false,
  },
};
```

For a custom menu icon 🌠 you don't have to hook up the `mousedown`/`click` in order to show or hide the menu - all this is done for you - just render your custom `ReactNode` and you're good to go.
