Context menu is only available in PRO version
ReactGrid comes with a custom context menu feature. Custom menu entries can be easily created thus
allowing for personalized experiences.
By default, the context menu is disabled. You can enable it by providing a handler function
to your ReactGrid using the onContextMenu property.
Enabling simple context menu
This guide is based on handling data changes.
- Update imports by adding Id,SelectionModeandMenuOptioninterfaces
import { ReactGrid, CellChange, Row, Column, Id, MenuOption, SelectionMode } from "@silevis/reactgrid";- Implement the context menu handler function
The menuOptions argument of simpleHandleContextMenu contains a list of default menu entries
provided by ReactGrid - copy, cut and paste.
For now, we'll simply define it, which will enable the default ReactGrid context menu.
const simpleHandleContextMenu = (
    selectedRowIds: Id[],
    selectedColIds: Id[],
    selectionMode: SelectionMode,
    menuOptions: MenuOption[]
  ): MenuOption[] => {
    return menuOptions;
};
 
return (
  <ReactGrid
    rows={rows}
    columns={columns}
    onCellsChanged={handleChanges}
    onContextMenu={simpleHandleContextMenu} // highlight-line
  />
);Here's the result. Right-click anywhere in the grid to see the context menu.
Code
const SimpleContextMenuHandlingSample = () => { const [columns] = React.useState<Column[]>(() => [ { columnId: "Name", width: 100 }, { columnId: "Surname", width: 100 } ]); const [rows, setRows] = React.useState<Row[]>(() => [ { rowId: 0, cells: [ { type: "header", text: "Name" }, { type: "header", text: "Surname" } ] }, { rowId: 1, cells: [ { type: "text", text: "Thomas" }, { type: "text", text: "Goldman" } ] }, { rowId: 2, cells: [ { type: "text", text: "Susie" }, { type: "text", text: "Spencer" } ] }, { rowId: 3, cells: [ { type: "text", text: "" }, { type: "text", text: "" } ] } ]); const handleChanges = (changes: CellChange[]) => { setRows((prevRows) => { changes.forEach((change) => { const changeRowIdx = prevRows.findIndex( (el) => el.rowId === change.rowId ); const changeColumnIdx = columns.findIndex( (el) => el.columnId === change.columnId ); prevRows[changeRowIdx].cells[changeColumnIdx] = change.newCell; }); return [...prevRows]; }); }; const simpleHandleContextMenu = ( selectedRowIds: Id[], selectedColIds: Id[], selectionMode: SelectionMode, menuOptions: MenuOption[] ): MenuOption[] => { return menuOptions; }; return ( <ReactGrid rows={rows} columns={columns} onCellsChanged={handleChanges} onContextMenu={simpleHandleContextMenu} /> ); } render(<SimpleContextMenuHandlingSample/>)
Preview
Advanced example - removing columns and rows
The default menu, though pretty, may seem a bit lacklustre when it comes to the functionality it provides. Let's try and extend it a bit - we'll make it possible to remove columns and rows using the context menu.
- Implement a more advanced context menu handler function
const handleContextMenu = (
  selectedRowIds: Id[],
  selectedColIds: Id[],
  selectionMode: SelectionMode,
  menuOptions: MenuOption[]
): MenuOption[] => {
  if (selectionMode === "row") {
    menuOptions = [
      ...menuOptions,
      {
        id: "removeRow",
        label: "Remove row",
        handler: () => setRows(rows.filter(row => !selectedRowIds.includes(row.rowId)))
      }
    ];
  }
  if (selectionMode === "column") {
    menuOptions = [
      ...menuOptions,
      {
        id: "removeColumn",
        label: "Remove column",
        handler: () => {
          const cols = columns.filter(column => !selectedColIds.includes(column.columnId));
          const columnsIdxs = columns
            .map((column, idx) => {
              if (!cols.includes(column)) return idx;
              return undefined;
            })
            .filter(idx => idx !== undefined);
          setRows(rows.map(row => ({
            ...row,
            cells: row.cells.filter((_, idx) => !columnsIdxs.includes(idx))
          })));
          setColumns(cols);
        }
      }
    ];
  }
  return menuOptions;
};- Update the ReactGridcomponent's properties. Note that columns and rows must be selectable for our feature to work. After all, we will be removing the currently selected row or column.
return (
  <ReactGrid
    rows={rows}
    columns={columns}
    onCellsChanged={handleChanges} // highlight-line
    onContextMenu={handleContextMenu} // highlight-line
    enableColumnSelection // highlight-line
    enableRowSelection // highlight-line
  />
)Live demo
You can see the effect of the changes we've just introduced in the demo below. To test the new feature, simply select a column or a row by clicking a header cell or one of the leftmost cells, then right-click anywhere and use the new menu entry.
Code
const AdvancedContextMenuHandlingSample = () => { const [columns, setColumns] = React.useState<Column[]>(() => [ { columnId: "Name", width: 100 }, { columnId: "Surname", width: 100 } ]); const [rows, setRows] = React.useState<Row[]>(() => [ { rowId: 0, cells: [ { type: "header", text: "Name" }, { type: "header", text: "Surname" } ] }, { rowId: 1, cells: [ { type: "text", text: "Thomas" }, { type: "text", text: "Goldman" } ] }, { rowId: 2, cells: [ { type: "text", text: "Susie" }, { type: "text", text: "Spencer" } ] }, { rowId: 3, cells: [ { type: "text", text: "" }, { type: "text", text: "" } ] } ]); const handleChanges = (changes: CellChange[]) => { setRows((prevRows) => { changes.forEach((change) => { const changeRowIdx = prevRows.findIndex( (el) => el.rowId === change.rowId ); const changeColumnIdx = columns.findIndex( (el) => el.columnId === change.columnId ); prevRows[changeRowIdx].cells[changeColumnIdx] = change.newCell; }); return [...prevRows]; }); }; const handleContextMenu = ( selectedRowIds: Id[], selectedColIds: Id[], selectionMode: SelectionMode, menuOptions: MenuOption[] ): MenuOption[] => { if (selectionMode === "row") { menuOptions = [ ...menuOptions, { id: "removeRow", label: "Remove row", handler: () => setRows(rows.filter(row => !selectedRowIds.includes(row.rowId))) } ]; } if (selectionMode === "column") { menuOptions = [ ...menuOptions, { id: "removeColumn", label: "Remove column", handler: () => { const cols = columns.filter(column => !selectedColIds.includes(column.columnId)); const columnsIdxs = columns .map((column, idx) => { if (!cols.includes(column)) return idx; return undefined; }) .filter(idx => idx !== undefined); setRows(rows.map(row => ({ ...row, cells: row.cells.filter((_, idx) => !columnsIdxs.includes(idx)) }))); setColumns(cols); } } ]; } return menuOptions; }; return ( <ReactGrid rows={rows} columns={columns} onCellsChanged={handleChanges} onContextMenu={handleContextMenu} enableFillHandle enableRangeSelection enableColumnSelection enableRowSelection /> ); } render(<AdvancedContextMenuHandlingSample/>)
Preview