Context menu in React TreeGrid
8 Oct 202524 minutes to read
The TreeGrid displays a context menu on right-click. Enable this feature by configuring default or custom items in the contextMenuItems property.
To use the context menu, inject the ContextMenu module in the TreeGrid.
The default items are listed below.
Items | Description
—-|—-
AutoFit | Auto-fit the current column.
AutoFitAll | Auto-fit all columns.
Edit | Edit the current record.
Delete | Delete the current record.
Save | Save the edited record.
Cancel | Cancel the edited state.
PdfExport | Export TreeGrid data as a PDF document.
ExcelExport | Export TreeGrid data as an Excel document.
CsvExport | Export TreeGrid data as a CSV document.
SortAscending | Sort the current column in ascending order.
SortDescending | Sort the current column in descending order.
FirstPage | Go to the first page.
PrevPage | Go to the previous page.
LastPage | Go to the last page.
NextPage | Go to the next page.
AddRow | Add a new row to the TreeGrid.
Indent | Indent the record by one hierarchy level.
Outdent | Outdent the record by one hierarchy level.
import { ColumnDirective, ColumnsDirective, Page, Resize, TreeGridComponent } from '@syncfusion/ej2-react-treegrid';
import { ContextMenu, Edit, ExcelExport, Inject, PdfExport, Sort } from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { sampleData } from './datasource';
function App() {
const editSettings = {
allowAdding: true,
allowDeleting: true,
allowEditing: true,
mode: 'Row'
};
const pageSettings = { pageSize: 7 };
const contextMenuItems = ['AutoFit', 'AutoFitAll',
'SortAscending', 'SortDescending', 'Edit', 'Delete', 'Save',
'Cancel', 'PdfExport', 'ExcelExport', 'CsvExport', 'FirstPage', 'PrevPage',
'LastPage', 'NextPage', 'Indent', 'Outdent'];
return <TreeGridComponent dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' allowPaging={true} pageSettings={pageSettings} allowSorting={true} allowResizing={true} editSettings={editSettings} allowPdfExport={true} allowExcelExport={true} contextMenuItems={contextMenuItems}>
<ColumnsDirective>
<ColumnDirective field='taskID' isPrimaryKey={true} headerText='Task ID' width='90' textAlign='Right'/>
<ColumnDirective field='taskName' headerText='Task Name' width='180'/>
<ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
<ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
</ColumnsDirective>
<Inject services={[Resize, Sort, Edit, ContextMenu, Page, PdfExport, ExcelExport]}/>
</TreeGridComponent>;
}
;
export default App;
import { ColumnDirective, ColumnsDirective, Page, Resize, TreeGridComponent } from '@syncfusion/ej2-react-treegrid';
import { ContextMenu, ContextMenuItem, Edit, ExcelExport, Inject, PdfExport, Sort, RowDD } from '@syncfusion/ej2-react-treegrid';
import { EditSettingsModel, PageSettingsModel } from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { sampleData } from './datasource';
function App() {
const editSettings: EditSettingsModel = {
allowAdding: true,
allowDeleting: true,
allowEditing: true,
mode: 'Row'
};
const pageSettings: PageSettingsModel = { pageSize: 7 };
const contextMenuItems: ContextMenuItem[] = ['AutoFit', 'AutoFitAll',
'SortAscending', 'SortDescending', 'Edit', 'Delete', 'Save',
'Cancel', 'PdfExport', 'ExcelExport', 'CsvExport', 'FirstPage', 'PrevPage',
'LastPage', 'NextPage', 'Indent', 'Outdent'];
return <TreeGridComponent dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks'
allowPaging={true} pageSettings={pageSettings} allowSorting={true} allowResizing={true}
editSettings={editSettings} allowPdfExport={true} allowExcelExport={true}
contextMenuItems={contextMenuItems}>
<ColumnsDirective>
<ColumnDirective field='taskID' isPrimaryKey={true} headerText='Task ID' width='90' textAlign='Right'/>
<ColumnDirective field='taskName' headerText='Task Name' width='180'/>
<ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
<ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
</ColumnsDirective>
<Inject services={[Resize, Sort, Edit, ContextMenu, Page, PdfExport, ExcelExport]}/>
</TreeGridComponent>
};
export default App;
Custom context menu items
Custom context menu items can be defined by setting contextMenuItems as a collection of contextMenuItemModel. Handle item actions in the contextMenuClick event.
In the following sample, a context menu item is added for parent rows to expand or collapse child rows.
import { getValue, isNullOrUndefined } from '@syncfusion/ej2-base';
import { ColumnDirective, ColumnsDirective, Page, TreeGridComponent } from '@syncfusion/ej2-react-treegrid';
import { ContextMenu, Inject } from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { sampleData } from './datasource';
function App() {
let treegrid;
const pageSettings = { pageSize: 7 };
const contextMenuItems = [
{ text: 'Collapse the Row', target: '.e-content', id: 'collapserow' },
{ text: 'Expand the Row', target: '.e-content', id: 'expandrow' }
];
const contextMenuClick = (args) => {
if (treegrid) {
treegrid.getColumnByField('taskID');
if (args.item.id === 'collapserow') {
treegrid.collapseRow(treegrid.getSelectedRows()[0], treegrid.getSelectedRecords()[0]);
}
else {
treegrid.expandRow(treegrid.getSelectedRows()[0], treegrid.getSelectedRecords()[0]);
}
}
};
const contextMenuOpen = (args) => {
const elem = args.event.target;
const uid = elem.closest('.e-row').getAttribute('data-uid');
if (treegrid) {
if (isNullOrUndefined(getValue('hasChildRecords', treegrid.grid.getRowObjectFromUID(uid).data))) {
args.cancel = true;
}
else {
const flag = getValue('expanded', treegrid.grid.getRowObjectFromUID(uid).data);
let val = flag ? 'none' : 'block';
document.querySelectorAll('li#expandrow')[0].setAttribute('style', 'display: ' + val + ';');
val = !flag ? 'none' : 'block';
document.querySelectorAll('li#collapserow')[0].setAttribute('style', 'display: ' + val + ';');
}
}
};
return <TreeGridComponent dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' allowPaging={true} pageSettings={pageSettings} allowSorting={true} allowResizing={true} contextMenuItems={contextMenuItems} contextMenuClick={contextMenuClick} ref={g => treegrid = g} contextMenuOpen={contextMenuOpen}>
<ColumnsDirective>
<ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'/>
<ColumnDirective field='taskName' headerText='Task Name' width='180'/>
<ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
<ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
</ColumnsDirective>
<Inject services={[ContextMenu, Page]}/>
</TreeGridComponent>;
}
;
export default App;
import { getValue, isNullOrUndefined } from '@syncfusion/ej2-base';
import { ContextMenuItemModel } from '@syncfusion/ej2-grids';
import { BeforeOpenCloseMenuEventArgs, MenuEventArgs } from '@syncfusion/ej2-navigations';
import { ColumnDirective, ColumnsDirective, Page, TreeGridComponent } from '@syncfusion/ej2-react-treegrid';
import { ContextMenu, Inject, PageSettingsModel, TreeGrid } from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { sampleData } from './datasource';
function App() {
let treegrid: TreeGridComponent | null;
const pageSettings: PageSettingsModel = { pageSize: 7 };
const contextMenuItems: ContextMenuItemModel[] = [
{text: 'Collapse the Row', target: '.e-content', id: 'collapserow'},
{text: 'Expand the Row', target: '.e-content', id: 'expandrow'}
];
const contextMenuClick = (args: MenuEventArgs): void => {
if (treegrid) {
treegrid.getColumnByField('taskID');
if (args.item.id === 'collapserow') {
treegrid.collapseRow(treegrid.getSelectedRows()[0] as HTMLTableRowElement,
treegrid.getSelectedRecords()[0]);
} else {
treegrid.expandRow(treegrid.getSelectedRows()[0] as HTMLTableRowElement,
treegrid.getSelectedRecords()[0]);
}
}
}
const contextMenuOpen = (args: BeforeOpenCloseMenuEventArgs): void => {
const elem: HTMLElement = args.event.target as HTMLElement;
const uid: string = (elem.closest('.e-row') as HTMLElement).getAttribute('data-uid') as string;
if (treegrid) {
if (isNullOrUndefined(getValue('hasChildRecords',
treegrid.grid.getRowObjectFromUID(uid) .data))) {
args.cancel = true;
} else {
const flag: boolean = getValue('expanded', treegrid.grid.getRowObjectFromUID(uid).data);
let val: string = flag ? 'none' : 'block';
document.querySelectorAll('li#expandrow')[0].setAttribute('style', 'display: ' + val + ';');
val = !flag ? 'none' : 'block';
document.querySelectorAll('li#collapserow')[0].setAttribute('style', 'display: ' + val + ';');
}
}
}
return <TreeGridComponent dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks'
allowPaging={true} pageSettings={pageSettings} allowSorting={true} allowResizing={true}
contextMenuItems={contextMenuItems} contextMenuClick={contextMenuClick}
ref={g => treegrid = g} contextMenuOpen={contextMenuOpen}>
<ColumnsDirective>
<ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'/>
<ColumnDirective field='taskName' headerText='Task Name' width='180'/>
<ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
<ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
</ColumnsDirective>
<Inject services={[ContextMenu, Page]}/>
</TreeGridComponent>
};
export default App;
Enable and disable context menu items dynamically
Enable or disable context menu items using the enableItems method within the contextMenuOpen event.
import { ColumnDirective, ColumnsDirective, Page, TreeGridComponent, ContextMenu, Edit, Inject } from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { sampleData } from './datasource';
function App() {
let treegrid;
const pageSettings = { pageSize: 7 };
const editSettings = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
mode: 'Row',
};
const contextMenuItems = [
{ text: 'Edit Record', target: '.e-content', id: 'Edit_record' },
{ text: 'Delete Record', target: '.e-content', id: 'Delete_record' },
];
const contextMenuClick = (args) => {
if (treegrid) {
if (args.element.innerHTML === 'Edit Record') {
treegrid.startEdit(args.rowInfo.row);
}
else if (args.element.innerHTML === 'Delete Record') {
treegrid.deleteRecord(args.rowInfo.row);
}
}
};
const contextMenuOpen = (args) => {
if (treegrid) {
if (args.rowInfo.rowData.hasChildRecords === true) {
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Edit Record'], true);
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Delete Record'], false);
}
else {
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Edit Record'], false);
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Delete Record'], true);
}
}
};
return <TreeGridComponent dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' pageSettings={pageSettings} editSettings={editSettings} contextMenuItems={contextMenuItems} contextMenuClick={contextMenuClick} ref={g => treegrid = g} contextMenuOpen={contextMenuOpen}>
<ColumnsDirective>
<ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'/>
<ColumnDirective field='taskName' headerText='Task Name' width='180'/>
<ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date'/>
<ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right'/>
</ColumnsDirective>
<Inject services={[ContextMenu, Page, Edit]}/>
</TreeGridComponent>;
}
;
export default App;
import { ContextMenuItemModel } from '@syncfusion/ej2-grids';
import { ColumnDirective, ColumnsDirective, EditSettingsModel, Page, TreeGridComponent,ContextMenu, Edit, Inject, PageSettingsModel, TreeGrid} from '@syncfusion/ej2-react-treegrid';
import * as React from 'react';
import { sampleData } from './datasource';
function App() {
let treegrid: TreeGridComponent | null;
const pageSettings: PageSettingsModel = { pageSize: 7 };
const editSettings: EditSettingsModel = {
allowEditing: true,
allowAdding: true,
allowDeleting: true,
mode: 'Row',
};
const contextMenuItems: ContextMenuItemModel[] = [
{ text: 'Edit Record', target: '.e-content', id: 'Edit_record' },
{ text: 'Delete Record', target: '.e-content', id: 'Delete_record' },
];
const contextMenuClick = (args: any): void => {
if (treegrid) {
if (args.element.innerHTML === 'Edit Record') {
treegrid.startEdit(args.rowInfo.row);
} else if (args.element.innerHTML === 'Delete Record') {
treegrid.deleteRecord(args.rowInfo.row);
}
}
}
const contextMenuOpen = (args: any): void => {
if (treegrid) {
if (args.rowInfo.rowData.hasChildRecords === true) {
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Edit Record'],true);
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Delete Record'],false);
} else {
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Edit Record'],false);
treegrid.grid.contextMenuModule.contextMenu.enableItems(['Delete Record'],true);
}
}
}
return <TreeGridComponent dataSource={sampleData} treeColumnIndex={1} childMapping='subtasks' pageSettings={pageSettings} editSettings = {editSettings} contextMenuItems={contextMenuItems} contextMenuClick={contextMenuClick} ref={g => treegrid = g} contextMenuOpen={contextMenuOpen}>
<ColumnsDirective>
<ColumnDirective field='taskID' headerText='Task ID' width='90' textAlign='Right'/>
<ColumnDirective field='taskName' headerText='Task Name' width='180'/>
<ColumnDirective field='startDate' headerText='Start Date' width='90' format='yMd' textAlign='Right' type='date' />
<ColumnDirective field='duration' headerText='Duration' width='80' textAlign='Right' />
</ColumnsDirective>
<Inject services={[ContextMenu, Page, Edit]}/>
</TreeGridComponent>
};
export default App;
Hide or show a context menu item for a specific area of the TreeGrid by configuring the targett) property.
Refer to the React TreeGrid feature tour page for highlights. Explore the React TreeGrid example to learn how to present and manipulate data.