Introduction
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 [people, setPeople] = React.useState<Person[]>(getPeople());
  const rows = getRows(people);
  const columns = getColumns();
 
  const handleChanges = (changes: CellChange[]) => {
    setPeople((prevPeople) => applyChangesToPeople(changes, prevPeople));
  };
 
  const simpleHandleContextMenu = (
    selectedRowIds: Id[],
    selectedColIds: Id[],
    selectionMode: SelectionMode,
    menuOptions: MenuOption[]
  ): MenuOption[] => {
    return menuOptions;
  }
 
  return (
    <ReactGrid
      rows={rows}
      columns={columns}
      onCellsChanged={handleChanges}
      onContextMenu={simpleHandleContextMenu}
    />
  );Here's the result. Right-click anywhere in the grid to see the context menu.
Code
interface Person { name: string; surname: string; } const getPeople = (): Person[] => [ { name: "Thomas", surname: "Goldman" }, { name: "Susie", surname: "Quattro" }, { name: "", surname: "" } ]; const getColumns = (): Column[] => [ { columnId: "name", width: 150 }, { columnId: "surname", width: 150 } ]; const headerRow: Row = { rowId: "header", cells: [ { type: "header", text: "Name" }, { type: "header", text: "Surname" } ] }; const getRows = (people: Person[]): Row[] => [ headerRow, ...people.map<Row>((person, idx) => ({ rowId: idx, cells: [ { type: "text", text: person.name }, { type: "text", text: person.surname } ] })) ]; const applyChangesToPeople = ( changes: CellChange[], prevPeople: Person[] ): Person[] => { changes.forEach((change) => { if (change.newCell.type === 'text') { const personIndex = change.rowId; const fieldName = change.columnId; prevPeople[personIndex][fieldName] = change.newCell.text; } }); return [...prevPeople]; }; const SimpleContextMenuHandlingSample = () => { const [people, setPeople] = React.useState<Person[]>(getPeople()); const rows = getRows(people); const columns = getColumns(); const handleChanges = (changes: CellChange[]) => { setPeople((prevPeople) => applyChangesToPeople(changes, prevPeople)); }; 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 people 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: "removePerson",
        label: "Remove person",
        handler: () => {
          setPeople(prevPeople => {
            return [...prevPeople.filter((person, idx) => !selectedRowIds.includes(idx))]
          })
        }
      }
    ];
  }
  return menuOptions;
}- Update the ReactGridcomponent's properties. Note that rows must be selectable for our feature to work. After all, we will be removing the currently selected rows.
return (
  <ReactGrid
    rows={rows}
    columns={columns}
    onCellsChanged={handleChanges}
    onContextMenu={handleContextMenu}
    enableFillHandle
    enableRangeSelection
    enableRowSelection
  />
)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 row by clicking a header cell or one of the leftmost cells, then right-click anywhere and use the new menu entry.
Code
interface Person { name: string; surname: string; } const getPeople = (): Person[] => [ { name: "Thomas", surname: "Goldman" }, { name: "Susie", surname: "Quattro" }, { name: "", surname: "" } ]; const getColumns = (): Column[] => [ { columnId: "name", width: 150 }, { columnId: "surname", width: 150 } ]; const headerRow: Row = { rowId: "header", cells: [ { type: "header", text: "Name" }, { type: "header", text: "Surname" } ] }; const getRows = (people: Person[]): Row[] => [ headerRow, ...people.map<Row>((person, idx) => ({ rowId: idx, cells: [ { type: "text", text: person.name }, { type: "text", text: person.surname } ] })) ]; const applyChangesToPeople = ( changes: CellChange[], prevPeople: Person[] ): Person[] => { changes.forEach((change) => { if (change.newCell.type === 'text') { const personIndex = change.rowId; const fieldName = change.columnId; prevPeople[personIndex][fieldName] = change.newCell.text; } }); return [...prevPeople]; }; const AdvancedContextMenuHandlingSample = () => { const [people, setPeople] = React.useState<Person[]>(getPeople()); const [columns] = React.useState<Column[]>(getColumns()); const rows = getRows(people); const handleChanges = (changes: CellChange[]) => { setPeople((prevPeople) => applyChangesToPeople(changes, prevPeople)); }; const handleContextMenu = ( selectedRowIds: Id[], selectedColIds: Id[], selectionMode: SelectionMode, menuOptions: MenuOption[] ): MenuOption[] => { if (selectionMode === "row") { menuOptions = [ ...menuOptions, { id: "removePerson", label: "Remove person", handler: () => { setPeople(prevPeople => { return [...prevPeople.filter((person, idx) => !selectedRowIds.includes(idx))] }) } } ]; } return menuOptions; } return ( <ReactGrid rows={rows} columns={columns} onCellsChanged={handleChanges} onContextMenu={handleContextMenu} enableRowSelection /> ); } render(<AdvancedContextMenuHandlingSample/>)
Preview