Context menu
Quickly access contextual actions such as removing rows, inserting columns or copying data, by opening the context menu.
Context menu with default options
Enable the context menu with the default configuration:
contextMenu: true,To see the context menu, right-click on a cell:
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'app-example1', template: ` <hot-table [settings]="hotSettings!" [data]="hotData"> </hot-table> `, standalone: false})export class AppComponent {
readonly hotData = [ ['', 'Tesla', 'Nissan', 'Toyota', 'Honda', 'Mazda', 'Ford'], ['2017', 10, 11, 12, 13, 15, 16], ['2018', 10, 11, 12, 13, 15, 16], ['2019', 10, 11, 12, 13, 15, 16], ['2020', 10, 11, 12, 13, 15, 16], ['2021', 10, 11, 12, 13, 15, 16], ];
readonly hotSettings: GridSettings = { rowHeaders: true, colHeaders: true, contextMenu: true, height: 'auto', autoWrapRow: true, autoWrapCol: true, };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
/* start:skip-in-compilation */import { AppComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ AppComponent ], providers: [...appConfig.providers], bootstrap: [ AppComponent ]})
export class AppModule { }/* end-file */<div> <app-example1></app-example1></div>Context menu with selected options
You can define the items in the menu by passing the contextMenu option as an array of keys:
| Key | Action and required plugins |
|---|---|
row_above | Insert a row above |
row_below | Insert a row below |
col_left | Insert a column to the left |
col_right | Insert a column to the right |
--------- | Add a separator to the items in the menu |
remove_row | Remove the selected row |
remove_col | Remove the selected column |
clear_column | Delete the data of the selected columns |
undo | Undo the last action. Requires: UndoRedo |
redo | Redo the last action. Requires: UndoRedo |
make_read_only | Make the selected cells read-only |
alignment | Align the text in the cell |
cut | Cut the contents of the selected cells to the system clipboard. Requires: CopyPaste |
copy | Copy the contents of the selected cells to the system clipboard. Requires: CopyPaste |
copy_with_column_headers | Copy the contents of the selected cells and their nearest column headers. Requires: CopyPaste with copyColumnHeaders set to true |
copy_with_column_group_headers | Copy the contents of the selected cells and all their related column headers. Requires: NestedHeaders and CopyPaste with copyColumnGroupHeaders set to true |
copy_column_headers_only | Copy the contents of column headers that are nearest to the selected cells. Requires: CopyPaste with copyColumnHeadersOnly set to true |
freeze_column | Freeze the selected column. Requires: ManualColumnFreeze |
unfreeze_column | Unfreeze the selected column. Requires: ManualColumnFreeze |
borders | Add borders around the selected cells. Requires: CustomBorders |
commentsAddEdit | Add or edit a comment. Requires: Comments |
commentsRemove | Remove the comment. Requires: Comments |
commentsReadOnly | Make the comment read-only. Requires: Comments |
mergeCells | Merge or unmerge the selected cells. Requires: MergeCells |
add_child | Insert a child row. Requires: NestedRows |
detach_from_parent | Detach the selected row from its parent row. Requires: NestedRows |
hidden_columns_hide | Hide the selected columns. Requires: HiddenColumns |
hidden_columns_show | Show the hidden columns. Requires: HiddenColumns |
hidden_rows_hide | Hide the selected rows. Requires: HiddenRows |
hidden_rows_show | Show hidden rows. Requires: HiddenRows |
filter_by_condition | Add the first filter condition. Requires: Filters |
filter_by_condition2 | Add the second filter condition. Requires: Filters |
filter_operators | Select a filter parameter. Requires: Filters |
filter_by_value | Add a filter value. Requires: Filters |
filter_action_bar | Apply the configured filter. Requires: Filters |
export_file | Open the Export submenu with “To CSV” and “To Excel” items. Requires: ExportFile. The Excel item is hidden when no XLSX engine is configured. |
To see the context menu, right-click on a cell:
/* file: app.component.ts */import { Component } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'app-example2', template: ` <hot-table [settings]="hotSettings!" [data]="hotData"> </hot-table> `, standalone: false})export class AppComponent {
readonly hotData = [ ['', 'Tesla', 'Nissan', 'Toyota', 'Honda', 'Mazda', 'Ford'], ['2017', 10, 11, 12, 13, 15, 16], ['2018', 10, 11, 12, 13, 15, 16], ['2019', 10, 11, 12, 13, 15, 16], ['2020', 10, 11, 12, 13, 15, 16], ['2021', 10, 11, 12, 13, 15, 16], ];
readonly hotSettings: GridSettings = { rowHeaders: true, colHeaders: true, contextMenu: ['row_above', 'row_below', 'remove_row', 'clear_column'], height: 'auto', autoWrapRow: true, autoWrapCol: true, };}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
/* start:skip-in-compilation */import { AppComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ AppComponent ], providers: [...appConfig.providers], bootstrap: [ AppComponent ]})
export class AppModule { }/* end-file */<div> <app-example2></app-example2></div>Context menu with a fully custom configuration
To fully customize the context menu, set contextMenu to an object with an items property. Each key in items identifies one menu entry. The value can be:
- A predefined item key string such as
'row_above'— includes the built-in item unchanged. - The string
'---------'— inserts a horizontal separator line. - A configuration object — defines a custom item or overrides a predefined one.
This means you can freely mix built-in items with custom ones in the same menu:
contextMenu: { // Optional: a shared callback fired on every item click. callback(key, selection, clickEvent) { console.log(key, selection, clickEvent); }, items: { row_above: {}, // predefined item, unchanged sp1: '---------', // separator row_below: { name: 'Click to add row below', // override a predefined item's label }, myOption: { // fully custom item name: 'My custom action', callback() { /* ... */ }, }, },},The top-level object also accepts a uiContainer property (an HTMLElement) to control which DOM element the context menu is appended to.
Menu item configuration options
Each configuration object in items can have these properties:
| Option | Description |
|---|---|
key | The unique identifier for the item. For top-level items, this is the key of the items object (for example 'row_above' or 'myOption'). For submenu items, it must follow the parent_key:child_key format (for example 'colors:red'). |
name | The label shown in the menu. Can be a string or a function returning a string. Supports HTML. When a function, this refers to the Handsontable instance. |
disabled | Whether the item is grayed out and non-clickable. Can be a boolean or a function returning a boolean. When a function, this refers to the Handsontable instance. |
hidden | Whether the item is hidden from the menu entirely. Can be a boolean or a function returning a boolean. When a function, this refers to the Handsontable instance. |
callback | A function called when the item is clicked. Receives key, selection, and clickEvent as arguments. |
submenu | Defines a nested submenu. Takes an object with an items array. Each submenu item’s key must follow the parent_key:child_key format. |
renderer | A custom function for rendering the item’s HTML. Must return an HTMLElement. |
disableSelection | When true, hovering over the item does not highlight it. |
isCommand | When false, clicking the item does not execute a command or close the menu. |
The following example shows how to:
- Add a shared callback for all options
- Dynamically disable an option
- Override the label of a predefined option
- Add a fully custom option with its own callback
- Add a custom option with a submenu
- Use a custom renderer
To see the context menu, right-click on a cell:
/* file: app.component.ts */import { Component, OnInit } from '@angular/core';import { GridSettings } from '@handsontable/angular-wrapper';
@Component({ selector: 'app-example3', template: ` <hot-table [settings]="hotSettings!" [data]="hotData"> </hot-table> `, standalone: false})export class AppComponent implements OnInit {
readonly hotData = [ ['', 'Tesla', 'Nissan', 'Toyota', 'Honda', 'Mazda', 'Ford'], ['2017', 10, 11, 12, 13, 15, 16], ['2018', 10, 11, 12, 13, 15, 16], ['2019', 10, 11, 12, 13, 15, 16], ['2020', 10, 11, 12, 13, 15, 16], ['2021', 10, 11, 12, 13, 15, 16], ];
hotSettings!: GridSettings;
ngOnInit() { const contextMenuSettings = { callback(key: string, selection: any, clickEvent: any) { // Common callback for all options console.log(key, selection, clickEvent); }, items: { row_above: { disabled(): boolean { // `disabled` can be a boolean or a function // Disable option when first row was clicked // @ts-ignore return this.getSelectedLast()?.[0] === 0; // `this` === hot }, }, // A separator line can also be added like this: // 'sp1': '---------' // and the key has to be unique sp1: { name: '---------' }, row_below: { name: 'Click to add row below', }, about: { // Own custom option name() { // `name` can be a string or a function return '<b>Custom option</b>'; // Name can contain HTML }, hidden(): boolean { // `hidden` can be a boolean or a function // Hide the option when the first column was clicked // @ts-ignore return this.getSelectedLast()?.[1] == 0; // `this` === hot }, callback() { // Callback for specific option setTimeout(() => { alert('Hello world!'); // Fire alert after menu close (with timeout) }, 0); }, }, colors: { // Own custom option name: 'Colors...', submenu: { // Custom option with submenu of items items: [ { // Key must be in the form 'parent_key:child_key' key: 'colors:red', name: 'Red', callback() { setTimeout(() => { alert('You clicked red!'); }, 0); }, }, { key: 'colors:green', name: 'Green' }, { key: 'colors:blue', name: 'Blue' }, ], }, }, credits: { // Own custom property // Custom rendered element in the context menu renderer() { const elem = document.createElement('marquee');
elem.style.cssText = 'background: lightgray; color: #222222;'; elem.textContent = 'Brought to you by...';
return elem; }, disableSelection: true, isCommand: false, }, }, };
this.hotSettings = { rowHeaders: true, colHeaders: true, licenseKey: 'non-commercial-and-evaluation', height: 'auto', contextMenu: contextMenuSettings, autoWrapRow: true, autoWrapCol: true, } }}/* end-file */
/* file: app.module.ts */import { NgModule, ApplicationConfig } from '@angular/core';import { BrowserModule } from '@angular/platform-browser';import { registerAllModules } from 'handsontable/registry';import { HOT_GLOBAL_CONFIG, HotGlobalConfig, HotTableModule } from '@handsontable/angular-wrapper';import { CommonModule } from '@angular/common';import { NON_COMMERCIAL_LICENSE } from '@handsontable/angular-wrapper';
/* start:skip-in-compilation */import { AppComponent } from './app.component';/* end:skip-in-compilation */
// register Handsontable's modulesregisterAllModules();
export const appConfig: ApplicationConfig = { providers: [ { provide: HOT_GLOBAL_CONFIG, useValue: { license: NON_COMMERCIAL_LICENSE, } as HotGlobalConfig } ],};
@NgModule({ imports: [ BrowserModule, HotTableModule, CommonModule ], declarations: [ AppComponent ], providers: [...appConfig.providers], bootstrap: [ AppComponent ]})
export class AppModule { }/* end-file */<div> <app-example3></app-example3></div>Related keyboard shortcuts
| Windows | macOS | Action | Excel | Sheets |
|---|---|---|---|---|
| Ctrl+Shift+\ or Shift+F10 | Cmd+Shift+\ or Shift+F10 | Open the context menu | ✗ | ✓ |
| Arrow keys | Arrow keys | Move one available menu item up, down, left, or right | ✓ | ✓ |
| Page Up | Page Up | Move to the first visible item of the context menu or submenu | ✓ | ✗ |
| Page Down | Page Down | Move to the last visible item of the context menu or submenu | ✓ | ✗ |
| Escape | Escape | Close the context menu or submenu | ✓ | ✓ |
| Enter | Enter | Run the action of the selected menu item | ✓ | ✗ |
Related articles
Related guides
Related blog articles
Configuration options
Hooks
Plugins