Context Menu
Module Extensions
Section titled “Module Extensions”HTMLRevoGridElement (Extended from global)
Section titled “HTMLRevoGridElement (Extended from global)”interface HTMLRevoGridElement { /** * Context menu configuration for row and body-cell targets. */ rowContextMenu?: ContextMenuConfig; /** * Context menu configuration for column-header targets. */ columnContextMenu?: ContextMenuConfig; /** * Legacy/shared context menu configuration. Used as a fallback when target-specific * row/column configs are not provided. */ contextMenu?: ContextMenuConfig; /** Kebab-case alias for framework/native custom element bindings. */ 'row-context-menu'?: ContextMenuConfig; /** Kebab-case alias for framework/native custom element bindings. */ 'column-context-menu'?: ContextMenuConfig; /** Kebab-case alias for framework/native custom element bindings. */ 'context-menu'?: ContextMenuConfig}AdditionalData (Extended from @revolist/revogrid)
Section titled “AdditionalData (Extended from @revolist/revogrid)”interface AdditionalData { /** * The context menu configuration for row and body-cell targets. * * @example * ```typescript * grid.additionalData = { * rowContextMenu: { items: [{ name: 'Edit', action: () => console.log('Edit action') }] }, * }; * ``` * * Prefer the direct `grid.rowContextMenu` property when the framework wrapper supports it. */ rowContextMenu?: ContextMenuConfig; /** * The context menu configuration for column-header targets. * * @example * ```typescript * grid.additionalData = { * columnContextMenu: { items: [{ name: 'Autosize', action: () => console.log('Autosize') }] }, * }; * ``` * * Prefer the direct `grid.columnContextMenu` property when the framework wrapper supports it. */ columnContextMenu?: ContextMenuConfig}Plugin API
Section titled “Plugin API”getContextMenuPrimaryShortcut
Section titled “getContextMenuPrimaryShortcut”export function getContextMenuPrimaryShortcut( key: string, platform = globalThis.navigator?.platform,): string;getContextMenuFilterPlugin
Section titled “getContextMenuFilterPlugin”Locate the active Core or Pro filter runtime without forcing filter setup.
export function getContextMenuFilterPlugin( context: ContextMenuActionContext,): ContextMenuFilterPlugin | undefined;openContextMenuColumnFilter
Section titled “openContextMenuColumnFilter”Open the existing filter popup while preserving the original synchronous API.
export function openContextMenuColumnFilter( context: ContextMenuActionContext, column: ColumnRegular,): boolean;openContextMenuColumnFilterAsync
Section titled “openContextMenuColumnFilterAsync”Open the existing filter popup and await its full async lifecycle.
export async function openContextMenuColumnFilterAsync( context: ContextMenuActionContext, column: ColumnRegular,): Promise<boolean>;ContextMenuPlugin
Section titled “ContextMenuPlugin”Adds configurable context menus to RevoGrid.
The plugin supports separate rowContextMenu and columnContextMenu
configurations while keeping contextMenu as a legacy fallback. Column menus
receive the current column, virtual column index, and column section, so a
single columnContextMenu can resolve different menu items for regular,
left-pinned, right-pinned, or specific columns.
Example:
import { ContextMenuPlugin } from '@revolist/revogrid-pro'
const grid = document.createElement('revo-grid');grid.plugins = [ContextMenuPlugin];grid.rowContextMenu = { items: [{ name: 'Delete row' }] };grid.columnContextMenu = { items: [{ name: 'Autosize column' }], resolve(context) { if (context.target === 'column' && context.columnType === 'colPinStart') { return { items: [{ name: 'Unpin left column' }] }; } },};Dependencies
Section titled “Dependencies”- Event integration
RowHeaderPlugin: Integrates with RowHeaderPlugin row menu events when present.
class ContextMenuPlugin { /** * Registers additive items that are resolved whenever a context menu opens. * * The application config and its `resolve` callback run first. Contributions * are then appended in ascending `order`, with registration order breaking * ties. The returned disposer is safe to call more than once. */ registerContribution(contribution: ContextMenuContribution): () => void;
/** * Applies defaults to a partial context menu config. * * @param config - User-provided menu config. * @param targetSelectors - Default selectors for the target-specific config. */ getConfig(config: Partial<ContextMenuConfig> = {}, targetSelectors: string[] = ['.rgCell']);
/** * Resolves a rendered header target to the same semantic column context used * by the shared context menu. */ resolveColumnContext( target: HTMLElement, event?: MouseEvent, ): ColumnContextMenuOpenContext;
/** * Hides the context menu popup without clearing the active config. */ close(restoreFocus = true);
/** * Opens the context menu for a DOM target. * * If `menuTarget` is provided, that target config is used directly. Otherwise * the plugin inspects the DOM target and chooses the column menu before the row * menu. The selected config is passed through `resolve` before rendering. * * @param target - Element that should anchor or identify the menu target. * @param event - Pointer event used for positioning and resolver context. * @param menuTarget - Optional explicit target used by row-header menu events. */ async open( target: EventTarget | null, event?: MouseEvent, menuTarget?: ContextMenuTarget, cell?: ContextMenuCellContext, );
clearSubscriptions();
destroy();}ContextMenuTarget
Section titled “ContextMenuTarget”Supported high-level targets for the context menu.
row covers body cells and row-menu buttons. column covers column header
cells, including pinned column sections.
/** * Supported high-level targets for the context menu. * * `row` covers body cells and row-menu buttons. `column` covers column header * cells, including pinned column sections. */export type ContextMenuTarget = 'row' | 'column';ContextMenuOpenContextBase
Section titled “ContextMenuOpenContextBase”Shared context passed to dynamic menu resolvers and menu item actions.
/** * Shared context passed to dynamic menu resolvers and menu item actions. */export type ContextMenuOpenContextBase = { /** The active menu target type. */ target: ContextMenuTarget; /** Element that caused the menu to open. */ triggerElement: HTMLElement; /** Mouse event that opened the menu, when opened from pointer interaction. */ triggerEvent?: MouseEvent; /** Grid element that owns the plugin instance. */ revogrid: HTMLRevoGridElement; /** Core plugin providers for data, dimensions, selection, columns, viewport, and plugins. */ providers: PluginProviders;};ContextMenuColumnGroup (Extended from index.ts)
Section titled “ContextMenuColumnGroup (Extended from index.ts)”export type ContextMenuColumnGroup = Group & { /** Grouping row depth in the header. */ depth?: number;};ColumnContextMenuOpenContext (Extended from index.ts)
Section titled “ColumnContextMenuOpenContext (Extended from index.ts)”Context available when a menu opens from a column header target.
/** * Context available when a menu opens from a column header target. */export type ColumnContextMenuOpenContext = ContextMenuOpenContextBase & { target: 'column'; /** Column model resolved from the header section and virtual column index. */ column?: ColumnRegular; /** Column group model resolved when opening from a grouped header cell. */ columnGroup?: ContextMenuColumnGroup; /** Physical column indexes covered by this menu target when it is a grouped header cell. */ columnIndexes?: number[]; /** Grouping row depth when opening from a grouped header cell. */ columnGroupDepth?: number; /** Virtual column index inside the current column section. */ columnIndex?: number; /** Column section that opened the menu: regular, left-pinned, or right-pinned. */ columnType?: DimensionCols;};RowContextMenuOpenContext (Extended from index.ts)
Section titled “RowContextMenuOpenContext (Extended from index.ts)”Context available when a menu opens from a row/body target.
/** * Context available when a menu opens from a row/body target. */export type RowContextMenuOpenContext = ContextMenuOpenContextBase & { target: 'row'; /** * Exact body cell that opened the menu. This remains distinct from the * current selection focus when a secondary click intentionally preserves an * existing range. */ cell?: ContextMenuCellContext;};ContextMenuCellContext
Section titled “ContextMenuCellContext”export type ContextMenuCellContext = Readonly< Omit<Pick< ColumnDataSchemaModel, | 'prop' | 'model' | 'column' | 'rowIndex' | 'colIndex' | 'colType' | 'type' | 'value' >, 'colType'> & { /** Data-column section or Core's dedicated row-header section. */ colType: DimensionCols | 'rowHeaders'; }>;ContextMenuOpenContext
Section titled “ContextMenuOpenContext”Union of all target-specific open contexts.
/** * Union of all target-specific open contexts. */export type ContextMenuOpenContext = ColumnContextMenuOpenContext | RowContextMenuOpenContext;ContextMenuConfigResolver
Section titled “ContextMenuConfigResolver”Dynamic menu resolver.
Return undefined to keep the base config, return a partial config to override
settings/items for this invocation, or return null to suppress the menu.
Example:
const columnContextMenu = { items: defaultItems, resolve(context) { if (context.target === 'column' && context.columnType === 'colPinStart') { return { items: pinnedColumnItems }; } },};/** * Dynamic menu resolver. * * Return `undefined` to keep the base config, return a partial config to override * settings/items for this invocation, or return `null` to suppress the menu. * * @example * ```ts * const columnContextMenu = { * items: defaultItems, * resolve(context) { * if (context.target === 'column' && context.columnType === 'colPinStart') { * return { items: pinnedColumnItems }; * } * }, * }; * ``` */export type ContextMenuConfigResolver = ( context: ContextMenuOpenContext,) => Partial<ContextMenuConfig> | null | undefined;ContextMenuContribution
Section titled “ContextMenuContribution”Additive context-menu items owned by an independent plugin or feature.
Contributions are resolved alongside the active application config and are composed before or after it without mutating that config.
/** * Additive context-menu items owned by an independent plugin or feature. * * Contributions are resolved alongside the active application config and are * composed before or after it without mutating that config. */export type ContextMenuContribution = { /** Identifier unique within one `ContextMenuPlugin` instance. */ readonly id: string; /** Ascending contribution order. Registration order breaks ties. */ readonly order?: number; /** * Places the contribution before or after the resolved application items. * Defaults to `append` for backward compatibility. */ readonly placement?: 'prepend' | 'append'; /** * Optional application-item filter for contexts owned by this contribution. * Return `false` to suppress a base item without mutating its source config. */ readonly filterBaseItem?: ( item: ContextMenuItem, context: ContextMenuOpenContext, ) => boolean; /** Optional policy applied to the complete menu after all contributions compose. */ readonly filterItem?: ( item: ContextMenuItem, context: ContextMenuOpenContext, ) => boolean; /** * Accessible popup name used when the application config does not provide * one. A later, more specific contribution overrides an earlier label. */ readonly ariaLabel?: string | ((context: ContextMenuOpenContext) => string | undefined); /** Resolves items for the current row or column menu invocation. */ readonly resolve: (context: ContextMenuOpenContext) => ContextMenuItem[];};ContextMenuActionContext
Section titled “ContextMenuActionContext”Context passed as the fifth argument to ContextMenuItem.action.
/** * Context passed as the fifth argument to `ContextMenuItem.action`. */export type ContextMenuActionContext = { /** Grid element that owns the plugin instance. */ revogrid: HTMLRevoGridElement, /** Core plugin providers for data, dimensions, selection, columns, viewport, and plugins. */ providers: PluginProviders, /** Context captured when this menu was opened. */ menu?: ContextMenuOpenContext,};ContextMenuItemStateResolver
Section titled “ContextMenuItemStateResolver”export type ContextMenuItemStateResolver = ( item: ContextMenuItem, focused?: Cell | null, range?: RangeArea | null,) => boolean;ContextMenuChildrenResolver
Section titled “ContextMenuChildrenResolver”export type ContextMenuChildrenResolver = ( focused?: Cell | null, range?: RangeArea | null, context?: ContextMenuActionContext,) => ContextMenuItem[];ContextMenuItem
Section titled “ContextMenuItem”Single menu item definition.
/** * Single menu item definition. */export type ContextMenuItem = { /** Stable identifier used by consumers and renderers. */ id?: string; /** * Item semantics. `separator` items ignore action, icon, checked, and * children. `heading` items are non-interactive menu context. Omitted kind * renders a standard menu item. */ kind?: 'item' | 'checkbox' | 'radio' | 'separator' | 'heading'; /** Text or dynamic text rendered inside the item. */ name: string | ((focused?: Cell | null, range?: RangeArea | null) => string); /** Secondary text rendered below a heading label. */ subtitle?: string; /** Accessible label when visible text is insufficient. */ ariaLabel?: string; /** Keyboard shortcut hint rendered at the trailing edge. */ shortcut?: string; /** Inline SVG rendered inside the trailing shortcut keycap. */ shortcutIcon?: string; /** Native tooltip text, useful for explaining a disabled action. */ title?: string; /** CSS class added to the `<li>` item. */ class?: string; /** Icon rendered before the item name. Accepts CSS classes or inline SVG markup. */ icon?: string; /** Apply the shared destructive-action presentation. */ danger?: boolean; /** CSS class added to the `<li>` item, optionally calculated from selection state. */ rowClass?: string | ((item: ContextMenuItem, focused?: Cell | null, range?: RangeArea | null) => string); /** Hide the item statically or from current selection state. */ hidden?: boolean | ContextMenuItemStateResolver; /** Disable the item statically or from current selection state while keeping it visible. */ disabled?: boolean | ContextMenuItemStateResolver; /** Checked state for checkbox and radio items. */ checked?: boolean | ContextMenuItemStateResolver; /** Logical group for radio items. */ radioGroup?: string; /** Nested submenu items or a resolver evaluated for the current menu context. */ children?: ContextMenuItem[] | ContextMenuChildrenResolver; /** Called when the item is selected. */ action?: (event: MouseEvent, focused?: Cell | null, range?: RangeArea | null, close?: () => void, context?: ContextMenuActionContext) => void; /** Keep the popup open after this item action runs. */ keepOpen?: boolean; /** Custom item renderer. */ template?: (h: HyperFunc<VNode>, item: ContextMenuItem, focused?: Cell | null, range?: RangeArea | null, close?: () => void) => any;};ContextMenuConfig
Section titled “ContextMenuConfig”Context menu configuration.
Use rowContextMenu for row/body targets and columnContextMenu for header
targets. resolve can refine either menu at open time for column sections,
individual columns, or any other target-specific condition.
/** * Context menu configuration. * * Use `rowContextMenu` for row/body targets and `columnContextMenu` for header * targets. `resolve` can refine either menu at open time for column sections, * individual columns, or any other target-specific condition. */export type ContextMenuConfig = { /** Items rendered in the popup. */ items: ContextMenuItem[]; /** Accessible name for the root menu. */ ariaLabel?: string; /** Open the menu on the native `contextmenu` event. Defaults to `true`. */ rightClick?: boolean; /** Open the menu on left click. Defaults to `false`. */ leftClick?: boolean; /** CSS selectors that can trigger this menu. */ targetSelectors?: string[]; /** Position the popup relative to the target element instead of pointer coordinates. */ anchorToTarget?: boolean; /** * Resolves a menu override for the current target before the menu opens. * Return `null` to suppress the menu for that target, `undefined` to use the base config, * or a partial config to override items/settings for this invocation. */ resolve?: ContextMenuConfigResolver;};ContextMenuPointerIntent
Section titled “ContextMenuPointerIntent”Keeps each open submenu stable while the pointer crosses its sibling rows. It does no continuous pointer tracking: decisions happen only on item entry.
class ContextMenuPointerIntent { enter( item: HTMLElement, event: Pick<MouseEvent, 'clientX' | 'clientY'>, activate: () => void, ): void;
enterSubmenu(item: HTMLElement): void;
reset(): void;}showContextMenuPopup
Section titled “showContextMenuPopup”Opens a context-menu element in the browser top layer when available. Browsers without the Popover API retain the existing display-based popup.
export function showContextMenuPopup(element: PopupElement): ContextMenuPopupMode;hideContextMenuPopup
Section titled “hideContextMenuPopup”Hides a popup opened by showContextMenuPopup; safe to call repeatedly.
export function hideContextMenuPopup( element: PopupElement, mode?: ContextMenuPopupMode,): void;calculateContextMenuPosition
Section titled “calculateContextMenuPosition”Resolves menu coordinates in the coordinate space of the supplied boundary. The caller converts the result to grid-local coordinates for the fallback.
export function calculateContextMenuPosition({ anchorRect, menuRect, boundary, anchorToTarget, pointer, inset = 0,}: ContextMenuPositionOptions): { top: number; left: number };ContextMenuPopupMode
Section titled “ContextMenuPopupMode”export type ContextMenuPopupMode = 'popover' | 'fallback';ContextMenuBoundary
Section titled “ContextMenuBoundary”export type ContextMenuBoundary = Pick< DOMRect, 'top' | 'right' | 'bottom' | 'left' | 'width' | 'height'>;ContextMenuPositionOptions
Section titled “ContextMenuPositionOptions”export type ContextMenuPositionOptions = { anchorRect: Pick<DOMRect, 'top' | 'right' | 'bottom' | 'left' | 'width' | 'height'>; menuRect: Pick<DOMRect, 'width' | 'height'>; boundary: ContextMenuBoundary; anchorToTarget: boolean; pointer?: Pick<MouseEvent, 'clientX' | 'clientY'>; inset?: number;};resolveGroupingRowCellContext
Section titled “resolveGroupingRowCellContext”Resolves Core’s full-width synthetic group renderer to a semantic cell-like
context. Group rows are intentionally not focusable and therefore do not
emit the normal beforecellfocus payload used by ordinary body cells.
export function resolveGroupingRowCellContext( target: HTMLElement, providers: PluginProviders,): ContextMenuCellContext | undefined;resolveRowHeaderCellContext
Section titled “resolveRowHeaderCellContext”Resolves a rendered row-header cell when Core does not emit the ordinary
beforecellfocus payload. Row headers share the row data store but live in
their own column viewport, so their context must be reconstructed from the
rendered virtual row index.
export function resolveRowHeaderCellContext( target: HTMLElement, providers: PluginProviders,): ContextMenuCellContext | undefined;isRowHeaderCellTarget
Section titled “isRowHeaderCellTarget”Whether a target belongs to Core’s dedicated row-header viewport.
export function isRowHeaderCellTarget(target: HTMLElement): boolean;DEFAULT_ROW_CONTEXT_MENU_TARGET_SELECTORS
Section titled “DEFAULT_ROW_CONTEXT_MENU_TARGET_SELECTORS”Core body targets that have row context-menu semantics.
DEFAULT_ROW_CONTEXT_MENU_TARGET_SELECTORS: string[];resetContextMenuPointerIntent
Section titled “resetContextMenuPointerIntent”export function resetContextMenuPointerIntent(element?: HTMLElement): void;resetContextMenuInteractionState
Section titled “resetContextMenuInteractionState”export function resetContextMenuInteractionState(element?: HTMLElement): void;renderMenuItemIcon
Section titled “renderMenuItemIcon”export function renderMenuItemIcon(icon?: string);normalizeContextMenuItems
Section titled “normalizeContextMenuItems”Resolves dynamic children and removes hidden, empty, leading, trailing, and consecutive separators without mutating application-owned menu items.
export function normalizeContextMenuItems( items: ContextMenuItem[], focused?: Cell | null, range?: RangeArea | null, context?: ContextMenuActionContext,): ContextMenuItem[];calculateContextSubmenuPosition
Section titled “calculateContextSubmenuPosition”export function calculateContextSubmenuPosition(input: { itemRect: Pick<DOMRect, 'top' | 'right' | 'left'>; menuRect: Pick<DOMRect, 'width' | 'height'>; viewportWidth: number; viewportHeight: number; inset?: number;});handleContextMenuKeyDown
Section titled “handleContextMenuKeyDown”export function handleContextMenuKeyDown(event: KeyboardEvent, close: () => void): void;contextPopUp
Section titled “contextPopUp”Extra VNode renderer registered by ContextMenuPlugin.
It reads the plugin instance state (config, activeContext, selection, and
close handler) and renders the current popup items. Menu item actions receive
the latest activeContext, which lets column menu actions know the exact
pinned section and column that opened the menu.
export function contextPopUp(this: { contextMenu?: HTMLElement | undefined; providers: PluginProviders; revogrid: HTMLRevoGridElement; config?: ContextMenuConfig; activeContext?: ContextMenuOpenContext; close: () => void;});POP_EL
Section titled “POP_EL”Registered extra VNode name for the context-menu popup.
The plugin uses this value to replace any previous popup renderer when the plugin is re-created, preventing duplicate popup nodes.
POP_EL: string;