How to prevent contextmenu depend on clicked cell's status?

Posted by: nguyenvu.work on 20 January 2026, 6:38 am EST

    • Post Options:
    • Link

    Posted 20 January 2026, 6:38 am EST

    • In my case, I want to prevent contextmenu if the clicked cell’s locked = true, I tried some solution such as switch
      workbook.options.allowContextMenu
      in binding
      SelectionChanging
      event, in
      GC.Spread.Sheets.CellTypes.Text.prototype.getHitInfo
      . That work well if I select cell then right click, but When I click to the first unlocked cell (contextmenu shown) then click to other locked cell (it doesn’t work, context menu still shown).
    • Are there any solution to resolve my issue?
  • Posted 20 January 2026, 9:28 am EST

    Hi,

    Thank you for reaching out! I understand you’re experiencing an issue where the context menu persists when right-clicking locked cells after initially right-clicking an unlocked cell.

    The solution you need is to intercept the context menu event at the host element level and check if the clicked cell is locked. Here’s the recommended approach:

    import * as GC from "@mescius/spread-sheets";
    
    const spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
    
    // Add context menu event listener to the spread host
    spread.getHost().addEventListener("contextmenu", (e) => {
        // Get the click coordinates relative to the spread container
        const offsetEle = spread.getHost();
        const x = e.pageX - offsetEle.offsetLeft;
        const y = e.pageY - offsetEle.offsetTop;
        
        // Perform hit test to identify the clicked element
        const target = spread.hitTest(x, y);
        const sheet = spread.getActiveSheet();
        const rowIndex = target.worksheetHitInfo.row;
        const colIndex = target.worksheetHitInfo.col;
    
        // Check if click is in viewport area and cell is locked
        if (target.worksheetHitInfo.hitTestType === GC.Spread.Sheets.SheetArea.viewport 
            && sheet.getCell(rowIndex, colIndex).locked()) {
            e.stopPropagation();
            e.preventDefault();
        }
    }, true); // Important: use capture phase
    
    const sheet = spread.getActiveSheet();
    
    // Example: Set up locked and unlocked cells
    sheet.getCell(1, 1).locked(false);
    sheet.getCell(1, 1).backColor("green");
    
    sheet.getCell(2, 2).locked(true);
    sheet.getCell(2, 2).backColor("red");
    

    Key Points:

    1. Event Listener on Host Element: The

      contextmenu
      event is attached directly to the spread host element, ensuring it captures all right-click events before SpreadJS processes them.

    2. Hit Test: Using

      spread.hitTest()
      with the click coordinates allows you to accurately determine which cell was clicked, regardless of the selection state.

    3. Capture Phase: The third parameter

      true
      in
      addEventListener
      ensures the event is captured in the capture phase, giving your handler priority over SpreadJS’s internal handlers.

    4. Conditional Prevention: The context menu is only prevented when:

      • The click is in the viewport area (not headers or other areas)
      • The target cell’s
        locked()
        property returns
        true

    Why This Works:

    Unlike the

    SelectionChanging
    event approach, this method doesn’t rely on cell selection state. It directly intercepts the context menu event and checks the locked state of the specific cell that was right-clicked, preventing the issue you experienced where the context menu would persist after clicking from an unlocked to a locked cell.

    This solution works consistently regardless of selection order or state changes.

    Sample: https://jscodemine.mescius.io/share/5PTBROmkXUCv9hMH-UxVWA/?defaultOpen={"OpenedFileName"%3A["%2Findex.html"%2C"%2Fpackage.json"%2C"%2Fsystemjs.config.js"%2C"%2Fsrc%2Fdata.js"%2C"%2Fsrc%2Fapp.js"]%2C"ActiveFile"%3A"%2Fsrc%2Fapp.js"}

    Regards,

    Priyam

  • Posted 22 January 2026, 12:53 am EST

    Thank you! It’s work. But with above codes, I replaced

      const offsetEle = spread.getHost();
      const x = e.pageX - offsetEle.offsetLeft;
      const y = e.pageY - offsetEle.offsetTop;
    

    by

     const rect = spreads.getBoundingClientRect();
     const x = e.clientX - rect.left;
     const y = e.clientY - rect.top;
    

    to get exact cell position, in my book, some row and col will be hidden, I think this is cause

    offsetEle
    is not work well.

  • Posted 22 January 2026, 5:57 am EST

    Hi,

    Yes, It appears using getBoundingClientRect() is the correct approach here when there is hidden elements.

    offsetLeft / offsetTop don’t account for scrolling, hidden rows/columns, or complex layouts, which can cause inaccurate hit testing.

    getBoundingClientRect() always reflects the actual rendered position, so the coordinates passed to spread.hitTest() remain accurate.

    Your change is valid and recommended for this scenario.

    Regards,

    Priyam

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels