Search results

How To

Data Binding

In the following example, menu items are populated from data source and mapped to items property.

Source
Preview
index.tsx
index.html
index.css
datasource.tsx
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Record, data } from 'datasource.tsx';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component<{}, {}> {

getMenuItems = () => {
let record: Record;
let menuItems: MenuItemModel[] = [];
for (let i: number = 0; i < data.length; i++) {
    record = data[i] as Record;
    if (record.parentId) {
        if (!menuItems[record.parentId - 1].items) {
            menuItems[record.parentId - 1].items = []
        }
        menuItems[record.parentId - 1].items.push({ text: record.text });
    } else {
        menuItems.push({ text: record.text });
    }
}
return menuItems;
}

itemBeforeEvent: any = (args: MenuEventArgs) => {
    if (!args.item.text) {
        args.element.classList.add('e-separator');
    }
}

render() {
return (
        <div class="container">
            <div id='target'>Right click / Touch hold to open the ContextMenu</div>
            <ContextMenuComponent id='contextmenu' target='#target'
            items={this.getMenuItems()} beforeItemRender={this.itemBeforeEvent}> </ContextMenuComponent>
        </div>
    );
}
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

#target {
	border: 1px dashed;
	height: 150px;
	padding: 10px;
	position: relative;
	text-align: justify;
	color: gray;
	user-select: none;
}
export let data: Record[] = [
    { id: 1, parentId: null, text: 'View' },
    { id: 2, parentId: null, text: 'Sort by' },
    { id: 3, parentId: null, text: '' },
    { id: 4, parentId: null, text: 'New' },
    { id: 5, parentId: null, text: '' },
    { id: 6, parentId: null, text: 'Display Settings' },
    { id: 7, parentId: null, text: 'Personalize' },
    //first level child
    { id: 8, parentId: 1, text: 'Large Icons' },
    { id: 9, parentId: 1, text: 'Medium Icons' },
    { id: 10, parentId: 1, text: 'Small Icons' },
    { id: 11, parentId: 2, text: 'Name' },
    { id: 12, parentId: 2, text: 'Size' },
    { id: 13, parentId: 4, text: 'Folder' },
    { id: 14, parentId: 4, text: 'Shortcut' },
    { id: 15, parentId: 4, text: '' },
    { id: 16, parentId: 4, text: 'Contact' }
];

export interface Record {
    id: number,
    parentId: number,
    text: string
}

Open and Close Context Menu

Open and close the ContextMenu manually whenever required by using open and close methods.

In the following sample, the ContextMenu is opened using the open method at the specified position with X and Y coordinates and to close the ContextMenu, close method is called internally on ContextMenu item click or document click.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component<{}, {}> {

menuItems: MenuItemModel[] = [
    {
        text: 'Cut'
    },
    {
        text: 'Copy'
    },
    {
        text: 'Paste'
    }
];

public btnClick(): void {
    var inst = document.getElementById('contextmenu').ej2_instances[0];
    inst.open(40, 20);
}

render() {
    return (
      <div class="container">
        <ContextMenuComponent id='contextmenu' items={ this.menuItems }></ContextMenuComponent>
        <ButtonComponent onClick={ this.btnClick }>Open ContextMenu</ButtonComponent>
      </div>
    );
  }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-react-buttons/styles/button/material.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

Change menu items dynamically

The items visible in the ContextMenu can be changed dynamically based on the context you open. To achieve this behavior, initialize ContextMenu with all items using items property and then based on the context you open hide/show required items using hideItems/showItems method in beforeOpen event.

In the following example, the datasource for Clipboard div is Cut, Copy, Paste and for the Editor div is Add, Edit, Delete is changed on beforeOpen event using hideItems and showItems method.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { BeforeOpenCloseMenuEventArgs } from '@syncfusion/ej2-navigations';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component {
  private menuItems: MenuItemModel[] = [
    {
        text: 'Cut'
    },
    {
        text: 'Copy'
    },
    {
        text: 'Paste'
    },
    {
        text: 'Add'
    },
    {
        text: 'Edit'
    },
    {
        text: 'Delete'
    }];

  beforeOpen: any = (args: BeforeOpenCloseMenuEventArgs) => {
      if ((args.event.target as HTMLElement).id === 'right') {
        this.cmenuInstance.hideItems(['Cut', 'Copy', 'Paste']);
        this.cmenuInstance.showItems(['Add', 'Edit', 'Delete']);
      } else if (args.event.target.id === 'left') {
        this.cmenuInstance.showItems(['Cut', 'Copy', 'Paste']);
        this.cmenuInstance.hideItems(['Add','Edit','Delete']);
      }
  }

  render() {
    return (
            <div class="container">
              <div id="target">
                 <div id='right' class='e-div'>Editor</div>
                 <div id='left' class='e-div'>Clipboard</div>
              </div>
              <ContextMenuComponent id='contextmenu' target='#target' ref={cmenu => this.cmenuInstance = cmenu}
              items={this.menuItems} beforeOpen={this.beforeOpen} beforeClose={this.beforeClose}> </ContextMenuComponent>
           </div>
        );
    }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
  color: #008cff;
  height: 40px;
  left: 45%;
  position: absolute;
  top: 45%;
  width: 30%;
}

#container {
  visibility: hidden;
}

#target {
  border: 1px dashed;
  height: 150px;
  padding: 10px;
  position: relative;
  text-align: justify;
  color: gray;
  user-select: none;
}

#right {
  float: right;
  border: 1px dashed;
  height: 98%;
  width: 48%;
}

#left {
  float: left;
  border: 1px dashed;
  height: 98%;
  width: 48%;
}

Scrollable ContextMenu

Scrollable ContextMenu can be achieved by restricting the height of the ul element.

In the following example, the height of the ContextMenu is set as 150px and overflow property is set as auto.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component<{}, {}> {

menuItems: MenuItemModel[] = [
    {
        text: 'ABS'
    },
    {
        text: 'ACOS'
    },
    {
        text: 'ACOSH'
    },
    {
        text: 'ACOT'
    },
    {
        text: 'ACOTH'
    },
    {
        text: 'AGGREGATE'
    },
    {
        text: 'COS'
    },
    {
        text: 'COSH'
    },
    {
        text: 'COT'
    },
    {
        text: 'COTH'
    }];

public btnClick(): void {
    var inst = document.getElementById('contextmenu').ej2_instances[0];
    inst.open(36, 10);
}

render() {
    return (
      <div class="container">
        <ContextMenuComponent id='contextmenu' items={ this.menuItems } cssClass='e-custom' ref={cmenu => this.cmenuInstance = cmenu}></ContextMenuComponent>
        <ButtonComponent onClick={ this.btnClick }>Formulas</ButtonComponent>
      </div>
    );
  }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-react-buttons/styles/button/material.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
  color: #008cff;
  height: 40px;
  left: 45%;
  position: absolute;
  top: 45%;
  width: 30%;
}

#container {
  visibility: hidden;
}

.e-custom ul {
  height: 150px;
  overflow: auto;
}

Templates

Table in Sub ContextMenu

Menu items of the ContextMenu can be customized according to the requirement. The section explains about how to customize table template in sub menu item.

This can be achieved by appending table layout while li rendering by using beforeItemRender event.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component<{}, {}> {

createHeader = () => {
let header: HTMLElement = document.createElement('h4');
header.textContent = 'Insert Table';
return header;
}
createTable = () => {
    let table: HTMLElement = document.createElement('table');
    for (let i: number = 0; i < 5; i++) {
        let row: HTMLElement = document.createElement('tr');
        table.appendChild(row);
    for (let j: number = 0; j < 6; j++) {
        let col: HTMLElement = document.createElement('td');
        row.appendChild(col);
        col.setAttribute('class', 'data');
    }
    }
    return table;
}

itemBeforeEvent: any = (args: MenuEventArgs) => {
    if (args.item.id === 'table') {
        args.element.classList.add('bg-transparent');
        args.element.appendChild(this.createHeader());
        args.element.appendChild(this.createTable());
    }
}

private menuItems: MenuItemModel[] = [
    {
        text: 'Cut',
        iconCss: 'e-cm-icons e-cut'
    },
    {
        text: 'Copy',
        iconCss: 'e-icons e-copy'
    },
    {
        text: 'Paste',
        iconCss: 'e-cm-icons e-paste'
    },
    {
        separator: true
    },
    {
        text: 'Link',
        iconCss: 'e-icons e-link'
    },
    {
        text: 'Table',
        iconCss: 'e-icons e-table',
        items: [
            {
                id: 'table'
            }
        ]
    }
];

render() {
    return (
        <div class="container">
            <div id='target'>Right click / Touch hold to open the ContextMenu</div>
            <ContextMenuComponent id='contextmenu' target='#target'
            items={this.menuItems} beforeItemRender={this.itemBeforeEvent}> </ContextMenuComponent>
        </div>
    );
}
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>
<style>
  .e-contextmenu-wrapper ul .e-menu-item.bg-transparent {
    background-color: transparent;
    line-height: normal;
    height: auto;
  }
  h4 {
    text-align: center;
    margin-top: 5px;
    margin-bottom: 5px;
  }
</style>
<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

#target {
	border: 1px dashed;
	height: 150px;
	padding: 10px;
	position: relative;
	text-align: justify;
	color: gray;
	user-select: none;
}

.data {
	border: 1px solid #212121;
	padding: 8px;
}

@font-face {
font-family: 'ddb-icons';
src:
url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAAKAIAAAwAgT1MvMj0gSRkAAAEoAAAAVmNtYXDnE+dkAAABlAAAADxnbHlmlh33NQAAAdwAAAJMaGVhZBKOK9sAAADQAAAANmhoZWEHeANwAAAArAAAACRobXR4E6AAAAAAAYAAAAAUbG9jYQGOAegAAAHQAAAADG1heHABEwBlAAABCAAAACBuYW1l1LBM9QAABCgAAAI9cG9zdMJntbUAAAZoAAAAUAABAAADUv9qAFoEAAAAAAADygABAAAAAAAAAAAAAAAAAAAABQABAAAAAQAAojXaQl8PPPUACwPoAAAAANfSc4gAAAAA19JziAAA//oDygPsAAAACAACAAAAAAAAAAEAAAAFAFkABAAAAAAAAgAAAAoACgAAAP8AAAAAAAAAAQPtAZAABQAAAnoCvAAAAIwCegK8AAAB4AAxAQIAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA5wDnAwNS/2oAWgPsAJYAAAABAAAAAAAABAAAAAPoAAAD6AAAA+gAAAPoAAAAAAACAAAAAwAAABQAAwABAAAAFAAEACgAAAAEAAQAAQAA5wP//wAA5wD//wAAAAEABAAAAAEAAgADAAQAAAAAAI4AwgEAASYAAwAA//oDNQPsAA4AHQBYAAAlHgEOAScmJy4BNz4BMzIFFgYHBgcGLgE2NzYzMhYBHgEXDgEHDgEHDgIWFxYXFjY3NjQ3PgE3HgEXFhQXHgE3PgE3PgEuAScuAScuASc+ATc+AQcLASYWAVEfFxo6IBkNCQIHCy8bCQG9BwIJDRkgOhoXHwoKGi/+TR1RDyEOIxo+ExckFAQMFikwVhcMBwYlFRYkBwcMF1YwFCALDAQUIxcUPhojDiAOUR4cAQvEwwsB6gtDTycJCBsSKxYhJ0gWKxIaCQknUEILAycCf2TPI0w2HBUmDg0sOzsaKQ4ONzcniyYXNBgYNBcmiyc3OA8GHRQaOzssDQ4mFRw2TiLOZGdBA/5vAZEDQQAEAAAAAAOqA+kABQANABcAHwAAARUzFSERAyERIzUjNSEBIREhESMVITUjMyMVITUjNSMC733+iT8B9D4+/oj+igE4AXc//c4++j8BOT+7AbZ8+gF2/ksBdz4//ksB9AF2fHw+Pj8AAAIAAAAAA7cD6QACACQAAAEhEwMOAQcVITUmJyY1ND8BIRcWFxYVFAcGKwEVITUmJyYnASMCKP8AguQrOy0BGkIRHREkASstEgEEDhQxEQGaJxUcLP7PDAFNAVL+PHBHCBsbBgsUKR8wX3owBg4NFgsQGxsDFx1zAyMAAAACAAAAAAPKA+oAAgATAAABFxEBDgEHHgEXETMRMxEzETM1IQL+zP1abpADA5t0f2F+XP41AfbMAZgBJwmYcHSbA/48A2r8lgNqfgAAAAASAN4AAQAAAAAAAAABAAAAAQAAAAAAAQAJAAEAAQAAAAAAAgAHAAoAAQAAAAAAAwAJABEAAQAAAAAABAAJABoAAQAAAAAABQALACMAAQAAAAAABgAJAC4AAQAAAAAACgAsADcAAQAAAAAACwASAGMAAwABBAkAAAACAHUAAwABBAkAAQASAHcAAwABBAkAAgAOAIkAAwABBAkAAwASAJcAAwABBAkABAASAKkAAwABBAkABQAWALsAAwABBAkABgASANEAAwABBAkACgBYAOMAAwABBAkACwAkATsgZGRiLWljb25zUmVndWxhcmRkYi1pY29uc2RkYi1pY29uc1ZlcnNpb24gMS4wZGRiLWljb25zRm9udCBnZW5lcmF0ZWQgdXNpbmcgU3luY2Z1c2lvbiBNZXRybyBTdHVkaW93d3cuc3luY2Z1c2lvbi5jb20AIABkAGQAYgAtAGkAYwBvAG4AcwBSAGUAZwB1AGwAYQByAGQAZABiAC0AaQBjAG8AbgBzAGQAZABiAC0AaQBjAG8AbgBzAFYAZQByAHMAaQBvAG4AIAAxAC4AMABkAGQAYgAtAGkAYwBvAG4AcwBGAG8AbgB0ACAAZwBlAG4AZQByAGEAdABlAGQAIAB1AHMAaQBuAGcAIABTAHkAbgBjAGYAdQBzAGkAbwBuACAATQBlAHQAcgBvACAAUwB0AHUAZABpAG8AdwB3AHcALgBzAHkAbgBjAGYAdQBzAGkAbwBuAC4AYwBvAG0AAAAAAgAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAQIBAwEEAQUBBgADY3V0CHBhc3RlXzAxBGZvbnQOcGFyYS1tYXJrLS0tMDMAAA==) format('truetype');
font-weight: normal;
font-style: normal;
}

.e-cm-icons {
 font-family: 'ddb-icons' !important;
speak: none;
font-size: 55px;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

.e-cut::before {
  content: '\e700';
}

.e-copy::before {
  content: '\e70a';
}

.e-paste::before {
  content: '\e701';
}

.e-link::before {
  content: '\e290';
}

.e-table::before {
  content: '\e705';
}

UI Components in ContextMenu

UI components can also be placed inside the each li element of ContextMenu.

In the following example, CheckBox component is placed inside each li element and this can be achieved by creating CheckBox component in beforeItemRender event and appending it into the li element.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { MenuEventArgs, BeforeOpenCloseMenuEventArgs } from '@syncfusion/ej2-navigations';
import { createCheckBox } from '@syncfusion/ej2-buttons';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { ButtonComponent } from '@syncfusion/ej2-react-buttons';
import { enableRipple, closest, createElement } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component<{}, {}> {

  menuItems: MenuItemModel[] = [
    {
        text: 'Option 1'
    },
    {
        text: 'Option 2'
    },
    {
        text: 'Option 3'
    }];
  itemBeforeEvent: any = (args: MenuEventArgs) => {
      let check: Element = createCheckBox(createElement, false, {
          label: args.item.text,
          checked: (args.item.text == 'Option 1'  || args.item.text == 'Option 2') ? true : false
      });
      args.element.innerHTML = '';
      args.element.appendChild(check);
  }

   beforeClose: any = (args: BeforeOpenCloseMenuEventArgs) => {
       if (args.event.target.closest('.e-menu-item')) {
            args.cancel = true;
            let selectedElem: NodeList = args.element.querySelectorAll('.e-selected');
            for(let i:number=0; i < selectedElem.length; i++){
            let ele: Element = selectedElem[i];
            ele.classList.remove('e-selected');
            }
            let checkbox: HTMLElement = closest(args.event.target as Element, '.e-checkbox-wrapper') as HTMLElement;
            let frame: HTMLElement = checkbox.querySelector('.e-frame');
            if (checkbox && frame.classList.contains('e-check')) {
                frame.classList.remove('e-check');
            } else if (checkbox) {
                frame.classList.add('e-check');
            }
       }
  }
render() {
    return (
      <div class="container">
        <div id='target'>Right click / Touch hold to open the ContextMenu</div>
        <ContextMenuComponent id='contextmenu' target='#target' items={this.menuItems} beforeItemRender={this.itemBeforeEvent} beforeClose={this.beforeClose}></ContextMenuComponent>
      </div>
    );
  }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

.e-link::before {
content: '\e7e8';
}

#target {
	border: 1px dashed;
	height: 150px;
	padding: 10px;
	position: relative;
	text-align: justify;
	color: gray;
	user-select: none;
}

Underline a character in the text

To underline a particular character in a text, it can be handled in beforeItemRender event by adding <u> tag in between the text and given as innerHTML in li rendering.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { MenuEventArgs } from '@syncfusion/ej2-navigations';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component {
  private menuItems: MenuItemModel[] = [
    {
        text: 'Cut'
    },
    {
        text: 'Copy'
    },
    {
        text: 'Paste'
    }];

  itemBeforeEvent: any = (args: MenuEventArgs) => {
      if (args.item.text === 'Copy') {
            args.element.innerHTML = '<u>C</u>opy';
      }
  }

  render() {
    return (
            <div class="container">
              <div id='target'>Right click / Touch hold to open the ContextMenu</div>
              <ContextMenuComponent id='contextmenu' target='#target'
              items={this.menuItems} beforeItemRender={this.itemBeforeEvent}> </ContextMenuComponent>
           </div>
        );
    }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

#target {
	border: 1px dashed;
	height: 150px;
	padding: 10px;
	position: relative;
	text-align: justify;
	color: gray;
	user-select: none;
}

Dialog Open On ContextMenu Item Click

This section explains about how to open a dialog on ContextMenu item click. This can be achieved by handling dialog open in select event of the ContextMenu.

In the following sample, Dialog will open while clicking Save As... item:

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { DialogComponent } from '@syncfusion/ej2-react-popups';
import { ContextMenuComponent, MenuItemModel, MenuEventArgs } from '@syncfusion/ej2-react-navigations';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component {
  private menuItems: MenuItemModel[] = [
    {
        text: 'Back'
    },
    {
        text: 'Forward'
    },
    {
        text: 'Reload'
    },
    {
        separator: true
    },
    {
        text: 'Save As...'
    },
    {
        text: 'Print'
    },
    {
        text: 'Cast'
    }];

  public position: any = { X: 100, Y:100 };
  public visible: boolean = false;
  public buttons: any = [{
        buttonModel: {
            isPrimary: true,
            content: 'Submit',
            cssClass: 'e-flat',
        },
        click: function () {
            this.hide();
        }
    }];
  select: any = (args: MenuEventArgs) => {
     if(args.item.text=== 'Save As...'){
        this.dialogInstance.show();
     }
    }
  render() {
    return (
            <div class="container">
              <div id='target'>Right click / Touch hold to open the ContextMenu</div>
              <DialogComponent
    width='200px' height='110px' content='This file can be saved as PDF' buttons={this.buttons} visible={this.visible} position={this.position} ref={dialog => this.dialogInstance = dialog}>
</DialogComponent>
              <ContextMenuComponent id='contextmenu' target='#target'
              items={this.menuItems} select={this.select}> </ContextMenuComponent>
           </div>
        );
    }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

#target {
  border: 1px dashed;
  height: 150px;
  padding: 10px;
  position: relative;
  text-align: justify;
  color: gray;
  user-select: none;
}

Change animation settings

To change the animation of the ContextMenu, animationSettings property is used. The supported effects for ContextMenu are,

Effect Functionality
None Specifies the sub menu transform with no animation effect.
SlideDown Specifies the sub menu transform with slide down effect.
ZoomIn Specifies the sub menu transform with zoom in effect.
FadeIn Specifies the sub menu transform with fade in effect.

The following sample illustrates how to open ContextMenu with FadeIn effect with the duration of 800ms.

Source
Preview
index.tsx
index.html
index.css
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { enableRipple } from '@syncfusion/ej2-base';

enableRipple(true);

export default class App extends React.Component {
  private animation: any = {
    effect: 'FadeIn',
    duration: 800
  };
  private menuItems: MenuItemModel[] = [
    {
        text: 'Show All Bookmarks'
    },
    {
        text: 'Bookmarks Toolbar',
        items: [
            {
                text: 'Most Visited',
                items: [
                    {
                        text: 'Google'
                    },
                    {
                        text: 'Gmail'
                    }
                ]
            },
            {
                text: 'Recently Added'
            }
        ]
    }];

  render() {
    return (
            <div class="container">
              <div id='target'>Right click / Touch hold to open the ContextMenu</div>
              <ContextMenuComponent id='contextmenu' target='#target'
              items={this.menuItems} animationSettings={this.animation}> </ContextMenuComponent>
           </div>
        );
    }
}

ReactDom.render(<App />,document.getElementById('element'));
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ContextMenu</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="//cdn.syncfusion.com/ej2/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-lists/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="//cdn.syncfusion.com/ej2/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
</head>

<body>
    <div id='element'>
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>
#loader {
	color: #008cff;
	height: 40px;
	left: 45%;
	position: absolute;
	top: 45%;
	width: 30%;
}

#target {
	border: 1px dashed;
	height: 150px;
	padding: 10px;
	position: relative;
	text-align: justify;
	color: gray;
	user-select: none;
}