Templates in React Context Menu

4 Sep 202624 minutes to read

Item template

The itemTemplate property in the Context Menu component allows you to define custom templates for displaying menu items. This feature enables you to customize the appearance, layout, and content of menu items beyond the default text-based display. Use item templates when you need to include icons, formatted text, additional metadata, or complex HTML structures within menu items.

import { enableRipple, Browser } from '@syncfusion/ej2-base';
import { ContextMenuComponent, MenuEventArgs, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import * as ReactDom from 'react-dom';

enableRipple(true);

function App() {
    const template = "<div class='menu-wrapper'><span class='${iconCss} icon-right'></span><div class='text-content'><span class='text'>${answerType}</span><span class='description'>${description}</span></div></div>";
    let content = Browser.isDevice ? 'Right-click or touch and hold to open the Context Menu and select the answer type' : 'Right click/Touch hold to open the Context Menu and select the answer type';

    // ContextMenu items definition
    const menuItems = [
        {
            answerType: 'Selection',
            description: "Choose from options",
            iconCss: 'e-icons e-list-unordered'
        },
        {
            answerType: 'Yes / No',
            description: "Select Yes or No",
            iconCss: 'e-icons e-check-box',
        },
        {
            answerType: 'Text',
            description: "Type own answer",
            iconCss: 'e-icons e-caption',
            items: [
                {
                    answerType: 'Single line',
                    description: "Type answer in a single line",
                    iconCss: 'e-icons e-text-form'
                },
                {
                    answerType: 'Multiple line',
                    description: "Type answer in multiple line",
                    iconCss: 'e-icons e-text-wrap'
                }
            ]
        },
        {
            answerType: 'None',
            iconCss: 'e-icons e-mouse-pointer',
            description: "No answer required"
        },
    ];

    const addTemplateClass = (args) => {
        if (args.element.classList.contains('e-ul')) {
            args.element.classList.add('e-contextMenu-template');
        }
    };

    return (
        <div className='control-pane'>
            <div className='control-section'>
                <div className='contextmenu-section'>
                    <div id='contextmenu-control'>
                        <div id="contextmenutarget">{content}</div>
                        <ContextMenuComponent
                            className="e-contextMenu-template"
                            target='#contextmenutarget'
                            items={menuItems}
                            itemTemplate={template}
                            beforeOpen={addTemplateClass}
                        />
                    </div>
                </div>
            </div>
        </div>
    );
}
export default App;
ReactDom.render(<App />, document.getElementById('element'));
import { enableRipple, Browser } from '@syncfusion/ej2-base';
import { ContextMenuComponent, MenuEventArgs, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import * as ReactDom from 'react-dom';

enableRipple(true);

function App() {
    const template: string = "<div class='menu-wrapper'><span class='${iconCss} icon-right'></span><div class='text-content'><span class='text'>${answerType}</span><span class='description'>${description}</span></div></div>";
    let content: string = Browser.isDevice ? 'Right-click or touch and hold to open the Context Menu and select the answer type' : 'Right click/Touch hold to open the Context Menu and select the answer type';

    // ContextMenu items definition
    const menuItems: any = [
        {
            answerType: 'Selection',
            description: "Choose from options",
            iconCss: 'e-icons e-list-unordered'
        },
        {
            answerType: 'Yes / No',
            description: "Select Yes or No",
            iconCss: 'e-icons e-check-box',
        },
        {
            answerType: 'Text',
            description: "Type own answer",
            iconCss: 'e-icons e-caption',
            items: [
                {
                    answerType: 'Single line',
                    description: "Type answer in a single line",
                    iconCss: 'e-icons e-text-form'
                },
                {
                    answerType: 'Multiple line',
                    description: "Type answer in multiple line",
                    iconCss: 'e-icons e-text-wrap'
                }
            ]
        },
        {
            answerType: 'None',
            iconCss: 'e-icons e-mouse-pointer',
            description: "No answer required"
        },
    ];

    const addTemplateClass = (args: MenuEventArgs) => {
        if (args.element.classList.contains('e-ul')) {
            args.element.classList.add('e-contextMenu-template');
        }
    };

    return (
        <div className='control-pane'>
            <div className='control-section'>
                <div className='contextmenu-section'>
                    <div id='contextmenu-control'>
                        <div id="contextmenutarget">{content}</div>
                        <ContextMenuComponent
                            className="e-contextMenu-template"
                            target='#contextmenutarget'
                            items={menuItems}
                            itemTemplate={template}
                            beforeOpen={addTemplateClass}
                        />
                    </div>
                </div>
            </div>
        </div>
    );
}

export default App;
ReactDom.render(<App />, document.getElementById('element'));

Customize specific menu items

The React Context Menu items can be customized using the beforeItemRender event. This event fires during rendering of each menu item. The handler receives a MenuEventArgs argument exposing:

Member Description
element The DOM node rendered for the menu item.
item The data object (MenuItemModel) for the menu item, used to read fields such as text, iconCss, and url.

The following example reads args.item.text to choose a keyboard shortcut and appends a <span> element to args.element during the rendering process. The createElement utility from @syncfusion/ej2-base is used to create the span element.

import { createElement, enableRipple } from '@syncfusion/ej2-base';
import { ContextMenuComponent } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import * as ReactDom from 'react-dom';
enableRipple(true);
function App() {
    let menuItems = [
        {
            text: 'Save as...'
        },
        {
            text: 'View page source'
        },
        {
            text: 'Inspect'
        }
    ];
    function itemBeforeEvent(args) {
        const shortCutSpan = createElement('span');
        const text = args.item.text;
        const shortCutText = text === 'Save as...' ? 'Ctrl + S' : (text === 'View page source' ? 'Ctrl + U' : 'Ctrl + Shift + I');
        shortCutSpan.textContent = shortCutText;
        args.element.appendChild(shortCutSpan);
        shortCutSpan.setAttribute('class', 'shortcut');
    }
    return (<div class="container">
              <div id='target'>Right click / Touch hold to open the ContextMenu</div>
              <ContextMenuComponent id='contextmenu' target='#target' items={menuItems} beforeItemRender={itemBeforeEvent}/>
           </div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('element'));
import { createElement, enableRipple } from '@syncfusion/ej2-base';
import { ContextMenuComponent, MenuEventArgs, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import * as ReactDom from 'react-dom';

enableRipple(true);

function App() {
  let menuItems: MenuItemModel[] = [
    {
        text: 'Save as...'
    },
    {
        text: 'View page source'
    },
    {
        text: 'Inspect'
    }];
    function itemBeforeEvent(args: MenuEventArgs) {
        const shortCutSpan = createElement('span');
        const text = args.item.text;
        const shortCutText = text === 'Save as...' ? 'Ctrl + S' : (text === 'View page source' ? 'Ctrl + U' : 'Ctrl + Shift + I');
        shortCutSpan.textContent = shortCutText;
        args.element.appendChild(shortCutSpan);
        shortCutSpan.setAttribute('class','shortcut');
    }

    return (
            <div class="container">
              <div id='target'>Right click / Touch hold to open the ContextMenu</div>
              <ContextMenuComponent id='contextmenu' target='#target'
              items={menuItems} beforeItemRender={itemBeforeEvent}/>
           </div>
        );
}
export default App;
ReactDom.render(<App />,document.getElementById('element'));

Multi-level nesting

The React Context Menu component supports multiple levels of nesting for creating hierarchical menu structures. Achieve this by mapping the items field of each parent menu item (see MenuItemModel.items) to an array of child MenuItemModel objects. By default, submenu items open on hover; the menu is not limited to a fixed nesting depth, but for usability we recommend keeping nesting to three or four levels. The following example demonstrates a three-level nested React Context Menu structure.

import * as React from 'react';
import * as ReactDom from 'react-dom';
import { ContextMenuComponent } from '@syncfusion/ej2-react-navigations';
import { enableRipple } from '@syncfusion/ej2-base';
enableRipple(true);
function App() {
    let menuItems = [
        {
            text: 'Show All Bookmarks'
        },
        {
            text: 'Bookmarks Toolbar',
            items: [
                {
                    text: 'Most Visited',
                    items: [
                        {
                            text: 'Google'
                        },
                        {
                            text: 'Gmail'
                        }
                    ]
                },
                {
                    text: 'Recently Added'
                }
            ]
        }
    ];
    return (<div class="container">
                <div id='target'>Right click / Touch hold to open the ContextMenu</div>
                <ContextMenuComponent id='contextmenu' target='#target' items={menuItems}> </ContextMenuComponent>
            </div>);
}
export default App;
ReactDom.render(<App />, document.getElementById('element'));
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);

function App() {
    let menuItems: MenuItemModel[] = [
    {
        text: 'Show All Bookmarks'
    },
    {
        text: 'Bookmarks Toolbar',
        items: [
            {
                text: 'Most Visited',
                items: [
                    {
                        text: 'Google'
                    },
                    {
                        text: 'Gmail'
                    }
                ]
            },
            {
                text: 'Recently Added'
            }
        ]
    }];

    return (
            <div class="container">
                <div id='target'>Right click / Touch hold to open the ContextMenu</div>
                <ContextMenuComponent id='contextmenu' target='#target'
                items={menuItems}> </ContextMenuComponent>
            </div>
        );
}
export default App;
ReactDom.render(<App />,document.getElementById('element'));

By default, submenu items open when the parent item is hovered. To open submenu items only on click, set the showItemOnClick property to true.

See also