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

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;
}

Note

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 prop.

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.

View Mode
Fork
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('https://infinite-table.com/.netlify/functions/json-server' + '/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, insideColumnMenu }) => {
      // if we're inside the column menu with all columns, return only the col name
      if (insideColumnMenu) {
        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>
          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 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 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.

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 prop. This prop can be a boolean or a function that returns a ReactNode.

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

Note

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.