Context Menu
ContextMenuManager provides a right-click context menu rendered as a DOM overlay. The menu supports keyboard navigation (arrow keys to move, Enter to select, Escape to close) and adapts its items based on click context — cell, header, row-number, or corner.
View source code
import { useRef, useEffect, useState } from 'react';import { WitTable } from '@witqq/spreadsheet-react';import type { WitTableRef } from '@witqq/spreadsheet-react';import { DemoWrapper } from './DemoWrapper';import { generateEmployees, employeeColumns } from './generate-data';import { useSiteTheme } from './useSiteTheme';
const data = generateEmployees(50);
export function ContextMenuDemo() { const { witTheme } = useSiteTheme(); const tableRef = useRef<WitTableRef>(null); const [lastAction, setLastAction] = useState('Right-click any cell, header, or row number to see the context menu.');
useEffect(() => { const engine = tableRef.current?.getInstance(); if (!engine) return; const cm = engine.getContextMenuManager(); if (!cm) return;
cm.registerItem({ id: 'highlight-row', label: '🟡 Highlight Row', contexts: ['cell', 'row-number'], action: (ctx) => setLastAction(`Highlighted row ${(ctx.row ?? 0) + 1}`), });
cm.registerItem({ id: 'column-info', label: 'ℹ️ Column Info', contexts: ['header'], action: (ctx) => { const col = employeeColumns[ctx.col ?? 0]; setLastAction(`Column: ${col?.title ?? 'unknown'}, type: ${col?.type ?? 'string'}`); }, });
cm.registerItem({ id: 'select-all', label: '☐ Select All', shortcut: 'Ctrl+A', contexts: ['corner'], action: () => setLastAction('Select all triggered from corner'), });
return () => { cm.unregisterItem('highlight-row'); cm.unregisterItem('column-info'); cm.unregisterItem('select-all'); }; }, []);
return ( <DemoWrapper title="Live Demo" description="Right-click cells, headers, row numbers, or the corner to see context-specific menus with custom items." height={440}> <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ padding: '0.5rem 0.75rem', fontSize: '0.8rem', color: '#64748b', borderBottom: '1px solid #e2e8f0', flexShrink: 0 }}> {lastAction} </div> <div style={{ flex: 1 }}> <WitTable theme={witTheme} ref={tableRef} columns={employeeColumns} data={data} showRowNumbers style={{ width: '100%', height: '100%' }} /> </div> </div> </DemoWrapper> );}Registering Custom Items
Section titled “Registering Custom Items”Add custom items to the context menu through the engine API:
import { useRef, useEffect } from 'react';import { WitTable, WitTableRef } from '@witqq/spreadsheet-react';
function App() { const ref = useRef<WitTableRef>(null);
useEffect(() => { const cm = ref.current?.getInstance().getContextMenuManager();
cm?.registerItem({ id: 'insert-row-above', label: 'Insert Row Above', shortcut: 'Ctrl+Shift+I', contexts: ['cell', 'row-number'], action: (ctx) => { console.log('Insert row above', ctx.row); }, });
cm?.registerItem({ id: 'format-column', label: 'Format Column', icon: '🎨', contexts: ['header'], action: (ctx) => { console.log('Format column', ctx.col); }, isDisabled: (ctx) => ctx.col === 0, });
return () => { cm?.unregisterItem('insert-row-above'); cm?.unregisterItem('format-column'); }; }, []);
return <WitTable ref={ref} columns={columns} data={data} />;}Context Regions
Section titled “Context Regions”Items appear based on their contexts array:
| Context | Trigger Area | Typical Actions |
|---|---|---|
cell | Any data cell | Copy, paste, insert, delete |
header | Column header | Sort, filter, resize, format |
row-number | Row number gutter | Insert row, delete row |
corner | Top-left corner cell | Select all, clear all |
API Reference
Section titled “API Reference”ContextMenuManager
Section titled “ContextMenuManager”| Method | Signature | Description |
|---|---|---|
registerItem | (item: ContextMenuItem) => void | Add menu item |
unregisterItem | (id: string) => void | Remove menu item |
close | () => void | Programmatically close menu |
ContextMenuItem
Section titled “ContextMenuItem”interface ContextMenuItem { id: string; label: string; icon?: string; shortcut?: string; contexts: Array<'cell' | 'header' | 'row-number' | 'corner'>; action: (ctx: MenuContext) => void; isDisabled?: (ctx: MenuContext) => boolean; isVisible?: (ctx: MenuContext) => boolean;}Plugin Integration
Section titled “Plugin Integration”When using the context menu as a plugin, use createContextMenuPlugin and its helper functions:
import { createContextMenuPlugin, createDefaultMenuItems } from '@witqq/spreadsheet-plugins';
const plugin = createContextMenuPlugin();engine.installPlugin(plugin);
// Get the default items (copy, paste, insert row, delete row, etc.)const defaultItems = createDefaultMenuItems();registerMenuItem / unregisterMenuItem
Section titled “registerMenuItem / unregisterMenuItem”Register or unregister items via the plugin API:
import { registerMenuItem, unregisterMenuItem } from '@witqq/spreadsheet-plugins';
registerMenuItem(pluginApi, { id: 'custom-action', label: 'Custom Action', contexts: ['cell'], action: (ctx) => console.log('Custom action on', ctx.row, ctx.col),});
unregisterMenuItem(pluginApi, 'custom-action');