Skip to content

Data Grid Context Menu & Formatting

DataGridContextMenuPlugin provides a complete, task-oriented menu without requiring every grid to define copy, edit, inspection, row, filter, formatting, sizing, grouping, column-management, and export actions from scratch. It auto-installs ContextMenuPlugin, ColumnDialogPlugin, Column Hide support, the cell inspector, and the spreadsheet formatting runtime.

Open the four-framework standalone example or browse its source in revogrid-demos/pro-data-grid-context-menu.

import { DataGridContextMenuPlugin } from '@revolist/revogrid-pro';
grid.plugins = [DataGridContextMenuPlugin];

Installing the plugin enables its defaults. Set the property to false to keep the plugin registered while suppressing the preset:

grid.dataGridContextMenu = false;

The preset is a prepended context-menu contribution. Existing rowContextMenu, columnContextMenu, and independent plugin contributions remain after it by default.

Hide or disable one generated command without rebuilding its parent submenu:

grid.dataGridContextMenu = {
hiddenItems: {
'row.delete': true,
},
disabledItems: {
'row.duplicate': context => context.rows.length > 20,
},
};

Resolvers receive a semantic DataGridContextMenuContext with the active surface, target rows, range, leaf columns, column group, and low-level menu context.

The surfaces are cell, rowHeader, rowGroup, columnHeader, and columnGroupHeader. Disable a whole surface with areas:

grid.dataGridContextMenu = {
areas: { rowGroup: false },
};

Use items for a simple extension. Use getItems when a surface needs complete replacement or transformation.

grid.dataGridContextMenu = {
items: context => [{
id: 'app.audit',
name: 'Open audit history',
action: () => openAuditHistory(context.rows[0]?.model),
}],
getItems: (context, defaults) =>
context.surface === 'columnGroupHeader'
? [{ id: 'app.groupSummary', name: 'Open group summary' }]
: defaults,
};

Set includeHostItems: false to suppress the application-provided base menu on enabled preset surfaces. Other plugin contributions still compose independently.

Every built-in command first emits a cancelable datagrid-context-menu-command event:

grid.addEventListener('datagrid-context-menu-command', event => {
if (event.detail.id === 'row.delete' && usesRemoteRows) {
event.preventDefault();
void deleteRowsOnServer(event.detail.context.rows);
}
});

A commandHandlers entry also replaces local behavior:

grid.dataGridContextMenu = {
commandHandlers: {
'row.delete': context => api.deleteRows(
context.rows.map(row => row.model.id),
),
},
};

Local row mutation is hidden for remote/server-grouped runtimes until a handler is provided. Clipboard permission and export failures emit datagrid-context-menu-error; Cut clears cells only after the clipboard write succeeds.

Commands appear only when their runtime exists. Add the matching plugin to expose filtering, Excel export, row selection, column auto-size, column collapse, tree, or server-grouping actions. Set unavailableItems: 'disable' to show unavailable commands in a disabled state instead.

grid.dataGridContextMenu = {
unavailableItems: 'disable',
rowPinning: true,
};

Row pinning is opt-in. Column insertion, duplication, and deletion are also opt-in and require an application factory so every new column receives a unique schema key:

grid.dataGridContextMenu = {
columnSchema: {
createColumn({ action, sourceColumn }) {
return {
...sourceColumn,
prop: `${String(sourceColumn.prop)}-${action}-${crypto.randomUUID()}`,
};
},
},
};

Cell and column-header menus include a type-aware Format submenu. Native numeric values expose Number, Currency, Accounting, Percentage, and Scientific presets; native Date values expose Date, Date & time, and Time. More formats… opens a separate Format Cells dialog for locale, decimal and date styles, font and fill, alignment, wrapping, borders, and a live preview.

See Format Cells for the complete popup guide, including selection behavior, stable row identity, render-time application, direct plugin usage, and runtime persistence limits.

Formatting changes presentation only. Raw source values used by editors, sorting, filtering, and formulas are not rewritten. Cell commands target the active range; column-header commands create a true column formatting default.

Map application column types explicitly when their values do not carry native number or Date types:

grid.dataGridContextMenu = {
formatting: {
locale: 'en-GB',
currencies: ['GBP', 'EUR', 'USD'],
getRowKey: row => row.id,
columnTypeKinds: {
money: 'number',
applicationDate: 'date',
},
},
};

Set formatting: false to remove the whole formatting submenu. Formatting commands respect grid and per-cell readonly rules. Value presets preserve authored custom cell templates; the rich dialog can still compose appearance through cellProperties without replacing interactive content.

Inspect cell opens a compact read-only popup for the exact invoked cell. It shows the column label and property, row dimension and authored source index, plus the raw value and its JavaScript type. The bounded serializer displays dates, undefined, bigint, symbols, functions, accessors, and circular references as selectable JSON-like inspection text without invoking getters or toJSON.

Full enumerable row snapshots are opt-in because source models can contain hidden or internal fields. Inspect column is available from leaf column headers and shows the property, pinned dimension, visible and physical indexes, type, readonly mode, sort order, filter configuration, rendered width, and authored width bounds. The complete resolved column definition is also opt-in because schema objects can contain private application metadata.

Limits and an application redaction hook are available when complete row or column inspection is appropriate:

grid.dataGridContextMenu = {
inspection: {
includeRowData: true,
includeColumnData: true,
serialization: { maxDepth: 5, maxEntries: 100, maxOutputLength: 20_000 },
redact(value, { kind }) {
return kind === 'row' || kind === 'column'
? redactPrivateFields(value)
: value;
},
localeText: { title: 'Cell details' },
},
};

The limits bound recursive traversal and rendered output after JavaScript has discovered an object’s own keys. They are not a sandbox for hostile Proxy traps or extremely wide objects; use redact to replace untrusted complex values.

Both inspectors remain available for readonly cells and readonly grids. Hide them like any other built-in item with hiddenItems: { 'cell.inspect': true, 'column.inspect': true }, or replace their behavior through the matching commandHandlers entry.