
Syncfusion React Menu
- 296 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
Use syncfusion-react-menu for development tasks
About
syncfusion-react-menu: A skill for development. This provides functionality for development workflows.
- syncfusion-react-menu
Syncfusion React Menu by the numbers
- 296 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,343 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-menuAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 296 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
What it does
Use syncfusion-react-menu for development tasks
Files
Implementing the Syncfusion React Menu Component
The Syncfusion React Menu component is a flexible, feature-rich navigation control for creating hierarchical menu structures with support for icons, separators, animations, accessibility, hamburger mode, scrolling, event handling, and item state management. Use it to build navigation bars, dropdown menus, context menus, mobile-responsive menus, and complex hierarchical navigation systems.
When to Use This Skill
- Building navigation menus: File menus, application menus, main navigation bars
- Dropdown menus: User action menus, context-sensitive options
- Sub-menu systems: Multi-level hierarchical navigation
- Hamburger/mobile menus: Responsive menu for mobile devices
- Menu customization: Adding/removing items, icons, separators, custom styling
- Event handling: Detecting menu item clicks, open/close events, item state changes
- Data-driven menus: Binding menus to JSON data structures (hierarchical or self-referential)
- Item state management: Enabling/disabling, showing/hiding, updating menu items
- Accessibility: Creating keyboard-navigable, screen reader-friendly menus
- RTL support: Right-to-left language menus
- Scrollable menus: Large menus with horizontal/vertical scrolling
- Persistence: Saving menu state across page reloads
Component Overview
Key Capabilities
- Hierarchical menus with unlimited nesting levels
- Data binding to hierarchical or self-referential JSON data
- Icon and separator support for visual organization
- Event system for click, open, close, and render interactions
- Animation effects with configurable timing and easing
- Keyboard navigation and WCAG accessibility compliance
- RTL support for right-to-left languages
- Responsive layout with horizontal and vertical scrolling
- Item state management - dynamically add, remove, enable/disable, show/hide items
- Hamburger mode for mobile-responsive menus
- State persistence - save and restore menu state across page reloads
- HTML sanitization for security
- Hover delay control for sub-menu timing
- Custom CSS classes for flexible styling
When to Choose Menu Over Alternatives
| Component | Best For |
|---|---|
| Menu | Hierarchical navigation, dropdown menus, file menus, hamburger menus |
| Navbar | Linear top navigation |
| Sidebar | Fixed side navigation panel |
| Tabs | Flat content sections with switching |
Quick Start
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import React from 'react';
function App() {
const menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
return (
<MenuComponent items={menuItems}></MenuComponent>
);
}
export default App;Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation and package setup with Vite/Create React App
- CSS imports and theme configuration
- Creating basic menu with MenuItemModel
- MenuComponent integration in React
- First render and initialization
- Ripple effects
- When to read: Starting a new Menu implementation, setting up project
Properties and Configuration
📄 Read: references/properties-and-configuration.md
- All MenuComponent properties with descriptions
- Default values and accepted types
- Configuration examples for each property
- animationSettings, cssClass, enableHtmlSanitizer, enablePersistence
- enableRtl, enableScrolling, hamburgerMode, hoverDelay
- locale, orientation, showItemOnClick, target, title
- When to read: Configuring component behavior, setting animations, enabling features
Methods and API
📄 Read: references/methods-api.md
- All MenuComponent methods with detailed documentation
- insertBefore(), insertAfter(), removeItems() - item manipulation
- enableItems(), hideItems(), showItems() - item state management
- getItemIndex(), setItem() - item access and updates
- open(), close() - hamburger mode control
- destroy() - cleanup
- Complete code examples for every method
- When to read: Dynamically manipulating menu items, controlling menu state
Events and Callbacks
📄 Read: references/events-and-callbacks.md
- All event types with complete documentation
- Event arguments: MenuEventArgs, BeforeOpenCloseMenuEventArgs, OpenCloseMenuEventArgs
- select, beforeOpen, beforeClose, onOpen, onClose events
- beforeItemRender and created lifecycle events
- Event handling patterns and callback examples
- When to read: Responding to user interactions, handling lifecycle events
Data Binding
📄 Read: references/data-binding.md
- Hierarchical data binding
- Self-referential data structures
- JSON data mapping with FieldSettingsModel
- Complex nested data hierarchies
- Dynamic data updates and modifications
- Real-time data from APIs
- When to read: Populating menus from data sources
Menu Item Customization
📄 Read: references/menu-items-customization.md
- Adding menu items with insertBefore/insertAfter
- Removing items with removeItems
- Enabling/disabling items with enableItems
- Showing/hiding items with showItems/hideItems
- Custom HTML attributes
- Separator support
- When to read: Dynamically managing menu structure
Styling and Appearance
📄 Read: references/styling-and-appearance.md
- Icon integration and positioning
- Separator rendering and customization
- Mnemonic UI creation (keyboard shortcuts)
- RTL (Right-to-left) support
- Custom CSS classes and theme integration
- Animation settings and effects
- Dark mode support
- When to read: Customizing appearance, theming
Hamburger and Mobile Mode
📄 Read: references/hamburger-mode.md
- Hamburger mode setup and configuration
- Mobile responsive implementation
- hamburgerMode, target, title properties
- open() and close() methods
- Integration with Sidebar and Accordion
- Mobile-first design patterns
- When to read: Building mobile-responsive menus
Use Case Scenarios
📄 Read: references/use-case-scenarios.md
- Scrollable menu implementation
- Menu in Toolbar integration
- Hamburger menu with Sidebar
- Mobile view with ListView
- Context menu patterns
- Dynamic data-driven menus
- When to read: Building specific menu patterns for real-world scenarios
Accessibility
📄 Read: references/accessibility.md
- WCAG compliance standards
- WAI-ARIA attributes
- Keyboard navigation patterns
- Screen reader support
- Focus management
- Color contrast guidelines
- Testing accessibility
- When to read: Ensuring menu is accessible to all users
Quick Start Example
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
// Define menu structure
const menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ separator: true },
{ text: 'Exit' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
},
{
text: 'Help'
}
];
return (
<MenuComponent items={menuItems}></MenuComponent>
);
}
export default App;Key Properties Reference
| Property | Type | Default | Purpose |
|---|---|---|---|
items | MenuItemModel[] | [] | Menu items to render |
fields | FieldSettingsModel | - | Data field mappings |
hamburgerMode | boolean | false | Enable mobile hamburger view |
enableScrolling | boolean | true | Allow scrolling for large menus |
enablePersistence | boolean | false | Save state across sessions |
enableRtl | boolean | false | Right-to-left text support |
orientation | Orientation | Horizontal | Layout direction |
animationSettings | MenuAnimationSettings | - | Animation configuration |
hoverDelay | number | 400 | Sub-menu hover delay (ms) |
showItemOnClick | boolean | false | Show items only on click |
enableHtmlSanitizer | boolean | true | Sanitize HTML content |
cssClass | string | - | Custom CSS classes |
locale | string | 'en-US' | Culture/language setting |
target | string | - | Element selector for hamburger |
title | string | - | Hamburger mode title text |
Key Methods Reference
| Method | Parameters | Purpose |
|---|---|---|
insertBefore() | item, selector | Insert before a menu item |
insertAfter() | item, selector | Insert after a menu item |
removeItems() | selectors | Remove items by selector |
enableItems() | selectors, enable | Enable/disable items |
showItems() | selectors | Show hidden items |
hideItems() | selectors | Hide visible items |
setItem() | item, selector | Update item properties |
getItemIndex() | selector | Get item index in menu |
open() | - | Open hamburger menu |
close() | - | Close hamburger menu |
destroy() | - | Cleanup component |
Key Events Reference
| Event | Trigger | Argument Type |
|---|---|---|
select | Menu item clicked | MenuEventArgs |
beforeOpen | Before sub-menu opens | BeforeOpenCloseMenuEventArgs |
beforeClose | Before sub-menu closes | BeforeOpenCloseMenuEventArgs |
onOpen | After sub-menu opens | OpenCloseMenuEventArgs |
onClose | After sub-menu closes | OpenCloseMenuEventArgs |
beforeItemRender | Before item renders | BeforeItemRenderEventArgs |
created | Component initialized | Object |
Common Patterns
Pattern 1: Responding to Menu Item Selection
const handleMenuSelect = (args) => {
console.log(`Selected: ${args.item.text}`);
// Handle the selected menu item
};
<MenuComponent
items={menuItems}
select={handleMenuSelect}
></MenuComponent>Pattern 2: Dynamically Adding Menu Items
let menuObj: MenuComponent;
const addMenuItem = () => {
menuObj.insertAfter([{ text: 'New Item' }], 'File');
};
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
></MenuComponent>Pattern 3: Disabling Menu Items
const handleBeforeOpen = (args) => {
if (args.item.text === 'Save') {
args.item.disabled = true; // Disable based on condition
}
};
<MenuComponent
items={menuItems}
beforeOpen={handleBeforeOpen}
></MenuComponent>Key Learning Path
1. Start Here: references/getting-started.md - Setup and basic menu creation 2. Add Data: references/data-binding.md - Bind menus to data sources 3. Handle Interaction: references/events-and-callbacks.md - Respond to user actions 4. Dynamic Control: references/methods-api.md - Manipulate menus programmatically 5. Advanced Features: references/hamburger-mode.md - Mobile-responsive patterns 6. Real-World Patterns: references/use-case-scenarios.md - Production implementations
All Reference Files
Fundamentals
- getting-started.md - Installation, setup, MenuItemModel structure
- properties-and-configuration.md - All 24+ component properties
Data & State
- data-binding.md - Hierarchical and self-referential binding
- menu-items-customization.md - Dynamic item management
Interaction & Control
- events-and-callbacks.md - Event system and callbacks
- methods-api.md - All methods for programmatic control
Presentation & UX
- styling-and-appearance.md - Icons, themes, animations
- orientation-and-layout.md - Horizontal/vertical layouts
- hamburger-mode.md - Mobile hamburger menus
- accessibility.md - WCAG compliance and keyboard navigation
Legacy (Original Files)
- events-and-interactions.md - Basic event handling (see events-and-callbacks.md for comprehensive documentation)
Real-World Implementation
- use-case-scenarios.md - 8 complete patterns: file menus, toolbars, sidebars, dashboards, mobile apps, etc.
Related Skills
- Implementing Sidebar - Side navigation panels
- Implementing AppBar - Top navigation/application bars
- Implementing Tabs - Tab-based content switching
- Implementing Accordion - Expandable content sections
- Implementing ListView - List-based navigation
Accessibility in React Menu Component
Table of Contents
- WCAG Compliance
- WAI-ARIA Attributes
- Keyboard Navigation
- Screen Reader Support
- Focus Management
- Color Contrast
- Accessible Menu Examples
- Testing for Accessibility
WCAG Compliance
The Syncfusion Menu component supports Web Content Accessibility Guidelines (WCAG) 2.1 standards at the AA level.
WCAG Principles Addressed
1. Perceivable: Menu structure visible and navigable 2. Operable: Full keyboard navigation support 3. Understandable: Clear labels and menu structure 4. Robust: Compatible with assistive technologies
Building WCAG-Compliant Menus
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function AccessibleApp() {
const menuItems: MenuItemModel[] = [
{
text: 'File',
id: 'menu-file',
htmlAttributes: {
'role': 'menuitem',
'aria-label': 'File menu',
'aria-expanded': 'false'
},
items: [
{
text: 'New',
id: 'menu-file-new',
htmlAttributes: {
'role': 'menuitem',
'aria-label': 'Create new file'
}
},
{
text: 'Open',
id: 'menu-file-open',
htmlAttributes: {
'role': 'menuitem',
'aria-label': 'Open existing file'
}
},
{
text: 'Exit',
id: 'menu-file-exit',
htmlAttributes: {
'role': 'menuitem',
'aria-label': 'Exit application'
}
}
]
}
];
return (
<MenuComponent
items={menuItems}
role="menubar"
aria-label="Main application menu"
></MenuComponent>
);
}
export default AccessibleApp;WAI-ARIA Attributes
Use WAI-ARIA attributes to enhance screen reader support:
Essential ARIA Attributes
const menuItems = [
{
text: 'File',
htmlAttributes: {
'role': 'menuitem',
'tabindex': '0',
'aria-label': 'File menu - use arrow keys to navigate',
'aria-expanded': 'false',
'aria-haspopup': 'menu'
},
items: [
{
text: 'New Document',
htmlAttributes: {
'role': 'menuitem',
'tabindex': '-1',
'aria-label': 'New Document - Create a new file'
}
}
]
}
];
<MenuComponent
items={menuItems}
role="menubar"
aria-label="Main Menu"
></MenuComponent>ARIA Attribute Reference
| Attribute | Value | Purpose |
|---|---|---|
role | menubar, menu, menuitem | Defines component type |
aria-label | String | Descriptive label for screen readers |
aria-expanded | true, false | Whether submenu is open |
aria-haspopup | menu, true | Indicates submenu exists |
aria-disabled | true, false | Item is disabled |
aria-hidden | true, false | Hide from assistive tech |
tabindex | 0, -1 | Keyboard focus order |
Keyboard Navigation
The Menu component supports full keyboard navigation:
Default Keyboard Shortcuts
| Key | Action |
|---|---|
Tab | Move focus to next menu item |
Shift+Tab | Move focus to previous menu item |
Enter/Space | Select focused menu item |
↑ Arrow | Move to previous item in menu |
↓ Arrow | Move to next item in menu |
← Arrow | Close submenu / move to parent |
→ Arrow | Open submenu / move to child |
Escape | Close menu and return focus |
Home | Move to first menu item |
End | Move to last menu item |
Alt+F | (With mnemonics) Open File menu |
Enabling Keyboard Navigation
function App() {
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
const handleKeyDown = (e) => {
// Menu handles keyboard automatically
// Additional custom keyboard handling if needed
console.log('Key pressed:', e.key);
};
return (
<MenuComponent
items={menuItems}
onKeyDown={handleKeyDown}
></MenuComponent>
);
}Custom Keyboard Handler
function App() {
let menuObj: MenuComponent;
const handleMenuKeyDown = (e) => {
// Handle custom keyboard shortcuts
if (e.altKey && e.key === 'f') {
// Alt+F to open File menu
e.preventDefault();
focusFileMenu();
}
};
React.useEffect(() => {
window.addEventListener('keydown', handleMenuKeyDown);
return () => window.removeEventListener('keydown', handleMenuKeyDown);
}, []);
return (
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
tabindex={0}
></MenuComponent>
);
}Screen Reader Support
Ensure menu content is properly announced by screen readers:
Descriptive Labels
const menuItems = [
{
text: 'File',
id: 'file-menu',
htmlAttributes: {
'aria-label': 'File menu containing document operations',
'role': 'menuitem',
'aria-expanded': 'false',
'aria-haspopup': 'menu'
},
items: [
{
text: 'New',
id: 'file-new',
htmlAttributes: {
'aria-label': 'Create a new document',
'aria-describedby': 'file-new-desc'
}
},
{
text: 'Open',
htmlAttributes: {
'aria-label': 'Open an existing document (Ctrl+O)',
'role': 'menuitem'
}
}
]
}
];
<MenuComponent items={menuItems}></MenuComponent>
// Hidden descriptions for screen readers
<p id="file-new-desc" style={{ display: 'none' }}>
Creates a new blank document
</p>Icon + Text Combinations
const menuItems = [
{
text: 'Save',
iconCss: 'e-icons e-save',
htmlAttributes: {
'aria-label': 'Save document (Ctrl+S)',
'role': 'menuitem',
'aria-describedby': 'save-description'
}
}
];
// Description for screen readers
<span id="save-description" className="sr-only">
Saves the current document to disk
</span>Focus Management
Proper focus management ensures keyboard users can navigate effectively:
Setting Initial Focus
function App() {
let menuObj: MenuComponent;
const setInitialFocus = () => {
// Set focus to first menu item on page load
const firstItem = menuObj.element?.querySelector('.e-menu-item');
firstItem?.focus();
};
React.useEffect(() => {
setInitialFocus();
}, []);
return (
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
></MenuComponent>
);
}Focus Restoration
function App() {
let menuObj: MenuComponent;
let previousFocus: HTMLElement | null = null;
const handleMenuOpen = (args) => {
// Store focus before opening menu
previousFocus = document.activeElement as HTMLElement;
};
const handleMenuClose = (args) => {
// Restore focus after closing menu
if (previousFocus) {
previousFocus.focus();
}
};
return (
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
open={handleMenuOpen}
close={handleMenuClose}
></MenuComponent>
);
}Focus Order and Tabindex
const menuItems = [
{
text: 'File',
htmlAttributes: {
'tabindex': '0' // Include in tab order
},
items: [
{
text: 'New',
htmlAttributes: {
'tabindex': '-1' // Skip in tab order (in submenu)
}
}
]
}
];
<MenuComponent items={menuItems}></MenuComponent>Color Contrast
Ensure sufficient color contrast between text and background:
WCAG AA Contrast Ratios
- Normal text: 4.5:1 minimum
- Large text: 3:1 minimum
- UI components: 3:1 minimum
High Contrast CSS
/* WCAG AA Compliant High Contrast Menu */
.accessible-menu .e-menu {
background-color: #ffffff;
border: 2px solid #000000; /* High contrast border */
}
.accessible-menu .e-menu-item {
color: #000000; /* Dark text on light background */
padding: 12px 16px;
min-height: 44px; /* Touch target size */
}
.accessible-menu .e-menu-item:hover {
background-color: #0066cc;
color: #ffffff;
border-left: 3px solid #ffcc00; /* High contrast indicator */
}
.accessible-menu .e-menu-item:focus {
outline: 3px solid #ffcc00;
outline-offset: 2px;
}
.accessible-menu .e-separator {
background-color: #000000; /* High contrast separator */
height: 2px;
margin: 8px 0;
}
.accessible-menu .e-menu-icon {
min-width: 24px;
min-height: 24px;
}Accessible Menu Examples
Example 1: Fully Accessible File Menu
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function AccessibleFileMenu() {
const menuItems: MenuItemModel[] = [
{
text: 'File',
id: 'file-menu',
iconCss: 'e-icons e-file',
htmlAttributes: {
'role': 'menuitem',
'aria-label': 'File menu',
'aria-expanded': 'false',
'aria-haspopup': 'menu'
},
items: [
{
text: 'New',
iconCss: 'e-icons e-new',
htmlAttributes: {
'aria-label': 'New document (Ctrl+N)',
'role': 'menuitem'
}
},
{
text: 'Open',
iconCss: 'e-icons e-open',
htmlAttributes: {
'aria-label': 'Open document (Ctrl+O)',
'role': 'menuitem'
}
},
{
separator: true,
htmlAttributes: { 'role': 'separator' }
},
{
text: 'Exit',
iconCss: 'e-icons e-exit',
htmlAttributes: {
'aria-label': 'Exit application',
'role': 'menuitem'
}
}
]
}
];
const handleMenuSelect = (args) => {
console.log(`Selected: ${args.item.text}`);
};
return (
<div className="accessible-menu-container">
<h1>File Manager</h1>
<MenuComponent
items={menuItems}
select={handleMenuSelect}
className="accessible-menu"
role="menubar"
aria-label="Main application menu"
></MenuComponent>
</div>
);
}
export default AccessibleFileMenu;Example 2: Accessible Navigation Menu
function AccessibleNavigation() {
const menuItems = [
{
text: 'Home',
url: '/',
htmlAttributes: {
'aria-label': 'Home page'
}
},
{
text: 'Products',
htmlAttributes: {
'aria-label': 'Products menu',
'aria-expanded': 'false'
},
items: [
{
text: 'Electronics',
htmlAttributes: { 'aria-label': 'Electronics products' }
},
{
text: 'Books',
htmlAttributes: { 'aria-label': 'Books and publications' }
}
]
},
{
text: 'About',
url: '/about',
htmlAttributes: {
'aria-label': 'About our company'
}
},
{
text: 'Contact',
url: '/contact',
htmlAttributes: {
'aria-label': 'Contact us page'
}
}
];
return (
<nav aria-label="Primary navigation">
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
className="accessible-nav"
></MenuComponent>
</nav>
);
}Testing for Accessibility
Keyboard Testing Checklist
- [ ] All menu items are reachable via Tab/Shift+Tab
- [ ] Arrow keys navigate within menu
- [ ] Enter/Space activates selected item
- [ ] Escape closes menu
- [ ] Focus indicators are visible
- [ ] Focus returns to trigger after menu closes
Screen Reader Testing
// Test with NVDA (Windows) or JAWS
// Verify screen reader announces:
// 1. Menu role and label
// 2. Item text and descriptions
// 3. Expanded/collapsed state
// 4. Disabled items
// 5. Keyboard shortcuts
// Use Chrome DevTools Accessibility Tree (Ctrl+Shift+I > Accessibility tab)Color Contrast Testing
// Use tools:
// - WebAIM Contrast Checker (webaim.org/resources/contrastchecker/)
// - Axe DevTools Chrome Extension
// - WAVE Browser Extension
// Verify:
// - Normal text: 4.5:1 ratio
// - Large text: 3:1 ratio
// - Focus indicators: 3:1 ratioAutomated Testing
import { axe, toHaveNoViolations } from 'jest-axe';
describe('Menu Accessibility', () => {
test('Menu should have no accessibility violations', async () => {
const { container } = render(
<MenuComponent items={menuItems}></MenuComponent>
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});Related Topics
- Getting Started - Basic setup
- Events and Interactions - Event handling
- Styling and Appearance - Visual customization
Data Binding in React Menu Component
Table of Contents
- Data Binding Overview
- Hierarchical Data Binding
- Self-Referential Data Binding
- FieldSettingsModel Configuration
- JSON Data Mapping
- Complex Nested Hierarchies
- Dynamic Data Updates
Data Binding Overview
The Menu component supports two primary data binding approaches:
1. Hierarchical Data: Direct nested structure with parent-child relationships 2. Self-Referential Data: Flat structure with ID/parent ID relationships
Both methods map custom data properties to Menu properties using FieldSettingsModel.
Hierarchical Data Binding
Hierarchical data uses nested arrays to represent menu levels. This is the most intuitive approach for organizing menu structures.
Basic Hierarchical Example
import { FieldSettingsModel, MenuComponent } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import './App.css';
function App() {
// Data source with nested structure
const dataSource = [
{
continent: 'Asia',
countries: [
{ country: 'China', capital: 'Beijing' },
{ country: 'India', capital: 'New Delhi' },
{ country: 'Japan', capital: 'Tokyo' }
]
},
{
continent: 'North America',
countries: [
{ country: 'Canada', capital: 'Ottawa' },
{ country: 'USA', capital: 'Washington' },
{ country: 'Mexico', capital: 'Mexico City' }
]
},
{
continent: 'Europe',
countries: [
{ country: 'France', capital: 'Paris' },
{ country: 'Germany', capital: 'Berlin' },
{ country: 'UK', capital: 'London' }
]
}
];
// Field mapping configuration
const fields: FieldSettingsModel = {
text: 'continent',
children: 'countries'
};
return (
<MenuComponent items={dataSource} fields={fields}></MenuComponent>
);
}
export default App;Multi-Level Hierarchical Structure
const dataSource = [
{
continent: 'Asia',
countries: [
{
country: 'China',
cities: [
{ city: 'Beijing' },
{ city: 'Shanghai' },
{ city: 'Guangzhou' }
]
},
{
country: 'India',
cities: [
{ city: 'Delhi' },
{ city: 'Mumbai' },
{ city: 'Bangalore' }
]
}
]
}
];
const fields: FieldSettingsModel = {
text: 'continent',
children: 'countries'
};
// For the second level, use nested fields configuration
const countriesFields: FieldSettingsModel = {
text: 'country',
children: 'cities'
};Self-Referential Data Binding
Self-referential data uses a flat structure where parent-child relationships are defined by ID/parent ID fields. This is useful for database-driven menus.
Self-Referential Structure
const dataSource = [
{
id: 1,
text: 'File',
parentId: null,
iconCss: 'e-icons e-file'
},
{
id: 2,
text: 'New',
parentId: 1,
iconCss: 'e-icons e-new'
},
{
id: 3,
text: 'Open',
parentId: 1,
iconCss: 'e-icons e-open'
},
{
id: 4,
text: 'Save',
parentId: 1,
iconCss: 'e-icons e-save'
},
{
id: 5,
text: 'Edit',
parentId: null,
iconCss: 'e-icons e-edit'
},
{
id: 6,
text: 'Cut',
parentId: 5,
iconCss: 'e-icons e-cut'
},
{
id: 7,
text: 'Copy',
parentId: 5,
iconCss: 'e-icons e-copy'
}
];
const fields: FieldSettingsModel = {
text: 'text',
parentId: 'parentId',
children: 'children',
iconCss: 'iconCss'
};
<MenuComponent items={dataSource} fields={fields}></MenuComponent>FieldSettingsModel Configuration
FieldSettingsModel maps custom data properties to Menu properties:
interface FieldSettingsModel {
// Property name for display text
text?: string;
// Property name for sub-items (hierarchical)
children?: string;
// Property name for parent ID (self-referential)
parentId?: string;
// Property name for item ID (self-referential)
itemId?: string;
// Property name for icon CSS class
iconCss?: string;
// Property name for URL (navigation link)
url?: string;
// Property name for separator flag
separator?: string;
// Property name for disabled flag
disabled?: string;
// Property name for hidden flag
hidden?: string;
// Property name for HTML attributes
htmlAttributes?: string;
}Mapping with Custom Property Names
// Data source with custom property names
const dataSource = [
{
label: 'File', // Custom text property
subItems: [ // Custom children property
{ label: 'New', icon: 'file-icon', isDisabled: false }
]
}
];
// Map custom properties
const fields: FieldSettingsModel = {
text: 'label', // Maps 'label' to menu text
children: 'subItems', // Maps 'subItems' to children
iconCss: 'icon', // Maps 'icon' to iconCss
disabled: 'isDisabled' // Maps 'isDisabled' to disabled
};
<MenuComponent items={dataSource} fields={fields}></MenuComponent>JSON Data Mapping
Complete example with comprehensive JSON data mapping:
import { FieldSettingsModel, MenuComponent } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
// Comprehensive JSON data source
const dataSource = [
{
menuId: 1,
menuText: 'File',
menuParent: null,
menuIcon: 'e-icons e-file',
submenus: [
{
menuId: 2,
menuText: 'New',
menuParent: 1,
menuIcon: 'e-icons e-new'
},
{
menuId: 3,
menuText: 'Open',
menuParent: 1,
menuIcon: 'e-icons e-open'
},
{
menuId: 4,
menuText: 'Save',
menuParent: 1,
menuIcon: 'e-icons e-save'
}
]
},
{
menuId: 5,
menuText: 'Edit',
menuParent: null,
menuIcon: 'e-icons e-edit',
submenus: [
{
menuId: 6,
menuText: 'Cut',
menuParent: 5,
menuIcon: 'e-icons e-cut'
},
{
menuId: 7,
menuText: 'Copy',
menuParent: 5,
menuIcon: 'e-icons e-copy'
},
{
menuId: 8,
menuText: 'Paste',
menuParent: 5,
menuIcon: 'e-icons e-paste'
}
]
}
];
// Field mapping
const fields: FieldSettingsModel = {
text: 'menuText',
children: 'submenus',
iconCss: 'menuIcon',
itemId: 'menuId',
parentId: 'menuParent'
};
return (
<MenuComponent
items={dataSource}
fields={fields}
></MenuComponent>
);
}
export default App;Complex Nested Hierarchies
Example with deeply nested menu structures (3+ levels):
const dataSource = [
{
category: 'Products',
items: [
{
subcategory: 'Electronics',
products: [
{
productName: 'Laptops',
models: [
{ model: 'XPS 15' },
{ model: 'ThinkPad X1' }
]
},
{
productName: 'Phones',
models: [
{ model: 'iPhone 14' },
{ model: 'Galaxy S23' }
]
}
]
},
{
subcategory: 'Accessories',
products: [
{
productName: 'Cables',
models: [
{ model: 'USB-C' },
{ model: 'HDMI' }
]
}
]
}
]
}
];
// Handle multiple nesting levels with recursive field mapping
const fields: FieldSettingsModel = {
text: 'category',
children: 'items'
};Dynamic Data Updates
Update menu data dynamically without recreating the component:
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
let menuObj: MenuComponent;
const [items, setItems] = React.useState([
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' }
]
}
]);
// Update menu items
const addNewCategory = () => {
const newItems = [...items, {
text: 'New Category',
items: [
{ text: 'Item 1' },
{ text: 'Item 2' }
]
}];
setItems(newItems);
};
// Modify existing data
const modifyMenuItem = () => {
const updatedItems = [...items];
updatedItems[0].items.push({ text: 'Save' });
setItems(updatedItems);
};
return (
<div>
<button onClick={addNewCategory}>Add Category</button>
<button onClick={modifyMenuItem}>Add Save Option</button>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={items}
></MenuComponent>
</div>
);
}
export default App;Real-Time Data from API
function App() {
const [menuData, setMenuData] = React.useState([]);
React.useEffect(() => {
// Fetch menu structure from API
fetch('/api/menu-structure')
.then(res => res.json())
.then(data => {
// Transform API response if needed
const transformedData = data.map(item => ({
text: item.name,
items: item.children
}));
setMenuData(transformedData);
});
}, []);
return <MenuComponent items={menuData}></MenuComponent>;
}Related Topics
- Menu Items Customization - Add/remove items dynamically
- Events and Interactions - Respond to data changes
Events and Callbacks
Table of Contents
1. Overview 2. Select Event 3. Open/Close Events 4. Before Events 5. Render Events 6. Lifecycle Events 7. Event Argument Types 8. Complete Examples
Overview
MenuComponent provides comprehensive event handling for user interactions and component lifecycle. Events are triggered at various points:
- User interactions (clicking, hovering)
- Menu opening/closing
- Item rendering
- Component initialization
Select Event
select
Event Name: select Type: EventEmitter<MenuEventArgs> Triggered: When a menu item is clicked
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
function App() {
const items: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
const handleSelect = (args) => {
console.log('Selected Item:', args.item.text);
console.log('Event Details:', args.event);
};
return (
<MenuComponent
items={items}
select={handleSelect}
/>
);
}
export default App;MenuEventArgs Structure
interface MenuEventArgs {
// The menu item that was selected
item: MenuItemModel;
// Original DOM event (MouseEvent or KeyboardEvent)
event: Event;
// Unique identifier for the menu
element: HTMLElement;
// Parent menu item (if item is in a sub-menu)
parentItem?: MenuItemModel;
// Current submenu's parent menu element
target?: HTMLElement;
}Open/Close Events
onOpen
Event Name: onOpen Type: EventEmitter<OpenCloseMenuEventArgs> Triggered: After a sub-menu has opened
function App() {
const items = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' }
]
}
];
const handleOpen = (args) => {
console.log('Sub-menu opened');
console.log('Parent item:', args.parentItem?.text);
console.log('Event type:', args.event);
};
return (
<MenuComponent
items={items}
onOpen={handleOpen}
/>
);
}
export default App;onClose
Event Name: onClose Type: EventEmitter<OpenCloseMenuEventArgs> Triggered: After a sub-menu has closed
function App() {
const items = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' }
]
}
];
const handleClose = (args) => {
console.log('Sub-menu closed');
console.log('Parent item:', args.parentItem?.text);
// Clean up or log analytics
};
return (
<MenuComponent
items={items}
onClose={handleClose}
/>
);
}
export default App;OpenCloseMenuEventArgs Structure
interface OpenCloseMenuEventArgs {
// The item whose sub-menu opened/closed
parentItem: MenuItemModel;
// The submenu element that opened/closed
element: HTMLElement;
// Original event (MouseEvent, KeyboardEvent, etc.)
event?: Event;
// Custom data if needed
[key: string]: any;
}Before Events
beforeOpen
Event Name: beforeOpen Type: EventEmitter<BeforeOpenCloseMenuEventArgs> Triggered: Before a sub-menu opens (cancellable)
function App() {
const items = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' }
]
},
{
text: 'Disabled Menu',
items: [
{ text: 'Item 1' }
]
}
];
const handleBeforeOpen = (args) => {
// Prevent opening if parent is "Disabled Menu"
if (args.parentItem.text === 'Disabled Menu') {
args.cancel = true; // Cancel the open action
console.log('Opening disabled menu prevented');
}
};
return (
<MenuComponent
items={items}
beforeOpen={handleBeforeOpen}
/>
);
}
export default App;beforeClose
Event Name: beforeClose Type: EventEmitter<BeforeOpenCloseMenuEventArgs> Triggered: Before a sub-menu closes (cancellable)
function App() {
const items = [
{
text: 'Tools',
items: [
{ text: 'Settings' },
{ text: 'Preferences' }
]
}
];
const handleBeforeClose = (args) => {
// Prevent closing if a specific item is selected
console.log('About to close sub-menu');
// You could prevent closing based on conditions
// args.cancel = true;
};
return (
<MenuComponent
items={items}
beforeClose={handleBeforeClose}
/>
);
}
export default App;BeforeOpenCloseMenuEventArgs Structure
interface BeforeOpenCloseMenuEventArgs {
// The item whose sub-menu is about to open/close
parentItem: MenuItemModel;
// The submenu element
element: HTMLElement;
// Original event
event?: Event;
// Set to true to cancel the operation
cancel: boolean;
}Render Events
beforeItemRender
Event Name: beforeItemRender Type: EventEmitter<BeforeItemRenderEventArgs> Triggered: Before each menu item is rendered (great for customization)
function App() {
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit', disabled: true },
{ id: 'help', text: 'Help' }
];
const handleBeforeItemRender = (args) => {
// Customize items before rendering
if (args.item.text === 'File') {
// Add custom class
if (!args.element.classList.contains('file-item')) {
args.element.classList.add('file-item');
}
}
// Add icons dynamically
if (args.item.text === 'Edit') {
args.element.style.opacity = '0.5';
}
};
return (
<MenuComponent
items={items}
beforeItemRender={handleBeforeItemRender}
/>
);
}
export default App;BeforeItemRenderEventArgs Structure
interface BeforeItemRenderEventArgs {
// The menu item about to be rendered
item: MenuItemModel;
// The DOM element for this item
element: HTMLElement;
// Whether item is in a sub-menu
isSubMenu: boolean;
// Parent element
parentElement: HTMLElement;
}Lifecycle Events
created
Event Name: created Type: EventEmitter<Object> Triggered: When the component is initialized and rendered
function App() {
const items = [
{ text: 'File' },
{ text: 'Edit' },
{ text: 'Help' }
];
const handleCreated = () => {
console.log('Menu component created and ready');
// Initialize tooltips, analytics tracking, etc.
};
return (
<MenuComponent
items={items}
created={handleCreated}
/>
);
}
export default App;Event Argument Types
Complete Reference
// MenuEventArgs - for select event
{
item: MenuItemModel;
event: MouseEvent | KeyboardEvent;
element: HTMLElement;
parentItem?: MenuItemModel;
target?: HTMLElement;
}
// OpenCloseMenuEventArgs - for onOpen, onClose
{
parentItem: MenuItemModel;
element: HTMLElement;
event?: Event;
}
// BeforeOpenCloseMenuEventArgs - for beforeOpen, beforeClose
{
parentItem: MenuItemModel;
element: HTMLElement;
event?: Event;
cancel: boolean;
}
// BeforeItemRenderEventArgs - for beforeItemRender
{
item: MenuItemModel;
element: HTMLElement;
isSubMenu: boolean;
parentElement: HTMLElement;
}Complete Examples
Example 1: Comprehensive Event Handling
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import { useState } from 'react';
function ComprehensiveEventExample() {
const [eventLog, setEventLog] = useState([]);
const items = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
const addLog = (message) => {
setEventLog(prev => [...prev, `[${new Date().toLocaleTimeString()}] ${message}`]);
};
const handleSelect = (args) => {
addLog(`✓ Selected: ${args.item.text}`);
};
const handleBeforeOpen = (args) => {
addLog(`→ Opening sub-menu for: ${args.parentItem.text}`);
};
const handleOnOpen = (args) => {
addLog(`◆ Opened: ${args.parentItem.text}`);
};
const handleBeforeClose = (args) => {
addLog(`← Closing sub-menu for: ${args.parentItem.text}`);
};
const handleOnClose = (args) => {
addLog(`◇ Closed: ${args.parentItem.text}`);
};
const handleCreated = () => {
addLog('★ Menu component created');
};
return (
<div className="event-demo">
<h2>Event Handling Demo</h2>
<div className="menu-container">
<MenuComponent
items={items}
select={handleSelect}
beforeOpen={handleBeforeOpen}
onOpen={handleOnOpen}
beforeClose={handleBeforeClose}
onClose={handleOnClose}
created={handleCreated}
/>
</div>
<div className="event-log">
<h3>Event Log</h3>
<div className="log-content">
{eventLog.map((log, idx) => (
<div key={idx} className="log-entry">{log}</div>
))}
</div>
</div>
</div>
);
}
export default ComprehensiveEventExample;Example 2: Conditional Menu Behavior
function ConditionalMenuApp() {
const [canAccessAdvanced, setCanAccessAdvanced] = useState(false);
const [itemsSelected, setItemsSelected] = useState([]);
const items = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ text: 'Save As' }
]
},
{
text: 'Advanced',
items: [
{ text: 'Settings' },
{ text: 'Debug Mode' },
{ text: 'Diagnostics' }
]
}
];
const handleBeforeOpen = (args) => {
// Prevent opening Advanced menu if not allowed
if (args.parentItem.text === 'Advanced' && !canAccessAdvanced) {
args.cancel = true;
alert('Advanced menu is not available');
}
};
const handleSelect = (args) => {
// Track selected items
setItemsSelected(prev => [...prev, args.item.text]);
};
return (
<div>
<div className="controls">
<label>
<input
type="checkbox"
checked={canAccessAdvanced}
onChange={(e) => setCanAccessAdvanced(e.target.checked)}
/>
Allow Advanced Menu
</label>
</div>
<MenuComponent
items={items}
beforeOpen={handleBeforeOpen}
select={handleSelect}
/>
<div className="status">
<h3>Selected Items:</h3>
<ul>
{itemsSelected.map((item, idx) => (
<li key={idx}>{item}</li>
))}
</ul>
</div>
</div>
);
}
export default ConditionalMenuApp;Example 3: Item Customization on Render
function CustomRenderExample() {
const items = [
{ text: 'Home', iconCss: 'e-icons e-home' },
{ text: 'Products', iconCss: 'e-icons e-box' },
{ text: 'About', iconCss: 'e-icons e-info' },
{ text: 'Contact', iconCss: 'e-icons e-mail' }
];
const handleBeforeItemRender = (args) => {
// Add custom styling based on item
if (args.item.text === 'Contact') {
args.element.classList.add('highlight');
}
// Add animation class
args.element.classList.add('fade-in');
// Customize based on submenu status
if (args.item.items) {
args.element.classList.add('has-submenu');
}
};
return (
<MenuComponent
items={items}
beforeItemRender={handleBeforeItemRender}
/>
);
}
export default CustomRenderExample;Best Practices
1. Use beforeOpen/beforeClose for validation - Prevent invalid operations before they occur 2. Handle select events for navigation - Direct users to appropriate pages/views 3. Log events for analytics - Track user interactions 4. Use beforeItemRender for styling - Apply dynamic classes/styles during rendering 5. Always provide feedback - Show users that their actions are registered
Related Topics
- Methods and API - Programmatic menu control
- Properties and Configuration - Event properties
- Menu Items Customization - Item manipulation with events
Events and Interactions in React Menu Component
Table of Contents
- Event System Overview
- Menu Item Selection Events
- Open and Close Events
- Event Arguments
- Preventing Default Actions
- Common Event Patterns
- Practical Workflows
Event System Overview
The Menu component provides a comprehensive event system for detecting user interactions:
| Event | Trigger | Usage |
|---|---|---|
select | Menu item clicked | Handle item selection |
beforeOpen | Before sub-menu opens | Modify/disable items |
beforeClose | Before sub-menu closes | Cleanup operations |
open | Sub-menu opened | Track menu state |
close | Sub-menu closed | Track menu state |
Menu Item Selection Events
The select Event
Triggered when a user clicks a menu item:
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
const handleMenuSelect = (args) => {
console.log(`Selected item: ${args.item.text}`);
console.log(`Parent: ${args.parentItem?.text}`);
// Perform action based on selected item
if (args.item.text === 'Save') {
saveDocument();
} else if (args.item.text === 'Exit') {
exitApplication();
}
};
const menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ separator: true },
{ text: 'Exit' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
return (
<MenuComponent
items={menuItems}
select={handleMenuSelect}
></MenuComponent>
);
}
export default App;Getting Selected Item Information
const handleMenuSelect = (args) => {
const selectedItem = args.item;
console.log('Item Properties:');
console.log(`- Text: ${selectedItem.text}`);
console.log(`- ID: ${selectedItem.id}`);
console.log(`- URL: ${selectedItem.url}`);
console.log(`- Icon: ${selectedItem.iconCss}`);
console.log(`- Disabled: ${selectedItem.disabled}`);
console.log(`- HTML Attributes:`, selectedItem.htmlAttributes);
// Parent information (for sub-items)
console.log(`Parent: ${args.parentItem?.text}`);
};Open and Close Events
beforeOpen Event
Triggered before a sub-menu opens. Use to modify items, update data, or prevent opening:
const handleBeforeOpen = (args) => {
console.log(`Opening: ${args.item.text}`);
// Modify items before they display
if (args.item.text === 'File') {
// Update menu items dynamically
args.item.items = getRecentFiles();
}
// Prevent opening if needed
if (shouldPreventOpen(args.item)) {
args.cancel = true;
}
};
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Recent Files' }
]
}
];
<MenuComponent
items={menuItems}
beforeOpen={handleBeforeOpen}
></MenuComponent>beforeClose Event
Triggered before a sub-menu closes:
const handleBeforeClose = (args) => {
console.log(`Closing: ${args.item.text}`);
// Perform cleanup
saveMenuState(args.item.text);
// Prevent closing if needed
if (hasUnsavedChanges()) {
args.cancel = true;
}
};
<MenuComponent
items={menuItems}
beforeClose={handleBeforeClose}
></MenuComponent>open and close Events
Triggered after menu opens/closes:
const handleOpen = (args) => {
console.log(`Opened: ${args.item.text}`);
// Track analytics, update UI state, etc.
};
const handleClose = (args) => {
console.log(`Closed: ${args.item.text}`);
// Cleanup after menu closes
};
<MenuComponent
items={menuItems}
open={handleOpen}
close={handleClose}
></MenuComponent>Event Arguments
MenuEventArgs (for select event)
interface MenuEventArgs {
// Item that was selected
item: MenuItemModel;
// Parent item (if item is a sub-menu)
parentItem?: MenuItemModel;
// Event object
event?: Event;
// Element that was clicked
element?: HTMLElement;
}OpenCloseMenuEventArgs
interface OpenCloseMenuEventArgs {
// Item being opened/closed
item: MenuItemModel;
// Enable/disable default action
cancel?: boolean;
// Items array being shown
items?: MenuItemModel[];
// Parent item
parentItem?: MenuItemModel;
// Event object
event?: Event;
}Preventing Default Actions
Cancel events to prevent default behavior:
const handleBeforeOpen = (args) => {
// Prevent opening File menu if user is not logged in
if (args.item.text === 'File' && !isUserLoggedIn()) {
args.cancel = true;
showLoginDialog();
}
};
const handleBeforeClose = (args) => {
// Prevent closing if there are unsaved changes
if (hasUnsavedChanges()) {
args.cancel = true;
showSavePrompt();
}
};Common Event Patterns
Pattern 1: Item Selection with Route Navigation
import { useNavigate } from 'react-router-dom';
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
function App() {
const navigate = useNavigate();
const handleMenuSelect = (args) => {
const routes: { [key: string]: string } = {
'Dashboard': '/dashboard',
'Profile': '/profile',
'Settings': '/settings'
};
const route = routes[args.item.text];
if (route) {
navigate(route);
}
};
const menuItems = [
{
text: 'Navigation',
items: [
{ text: 'Dashboard' },
{ text: 'Profile' },
{ text: 'Settings' }
]
}
];
return (
<MenuComponent
items={menuItems}
select={handleMenuSelect}
></MenuComponent>
);
}Pattern 2: Dynamic Menu Updates on Open
const handleBeforeOpen = async (args) => {
if (args.item.text === 'Recent Files') {
try {
// Fetch recent files from API
const recentFiles = await fetchRecentFiles();
// Update menu items
args.item.items = recentFiles.map(file => ({
text: file.name,
url: file.path
}));
// Set flag to prevent re-fetching
args.item.dataLoaded = true;
} catch (error) {
console.error('Failed to load recent files:', error);
}
}
};Pattern 3: Conditional Item Disabling
const handleBeforeOpen = (args) => {
// Disable Edit menu if nothing is selected
if (args.item.text === 'Edit') {
args.item.items.forEach(item => {
if (['Cut', 'Copy', 'Delete'].includes(item.text)) {
item.disabled = !hasSelection();
}
});
}
// Disable Paste if clipboard is empty
if (args.item.text === 'Edit') {
args.item.items.forEach(item => {
if (item.text === 'Paste') {
item.disabled = !hasClipboardContent();
}
});
}
};showItemOnClick Property
By default, sub-menus open on hover. Set showItemOnClick to open on click:
function App() {
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
}
];
// Open sub-menus on click instead of hover
return (
<MenuComponent
items={menuItems}
showItemOnClick={true}
></MenuComponent>
);
}Combined with select event:
function App() {
const handleMenuSelect = (args) => {
console.log(`Clicked: ${args.item.text}`);
// Perform action immediately
if (!args.item.items) {
executeMenuAction(args.item.text);
}
};
return (
<MenuComponent
items={menuItems}
showItemOnClick={true}
select={handleMenuSelect}
></MenuComponent>
);
}Practical Workflows
Workflow 1: Menu with Action Confirmation
function App() {
let menuObj: MenuComponent;
const [showConfirm, setShowConfirm] = React.useState(false);
const [selectedAction, setSelectedAction] = React.useState(null);
const handleMenuSelect = (args) => {
// Actions requiring confirmation
if (['Delete', 'Clear Cache', 'Reset'].includes(args.item.text)) {
setSelectedAction(args.item.text);
setShowConfirm(true);
} else {
executeAction(args.item.text);
}
};
const confirmAction = () => {
executeAction(selectedAction);
setShowConfirm(false);
};
const menuItems = [
{
text: 'Tools',
items: [
{ text: 'Delete' },
{ text: 'Clear Cache' },
{ text: 'Reset' }
]
}
];
return (
<>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
select={handleMenuSelect}
></MenuComponent>
{showConfirm && (
<div className="confirmation-dialog">
<p>Confirm: {selectedAction}?</p>
<button onClick={confirmAction}>Confirm</button>
<button onClick={() => setShowConfirm(false)}>Cancel</button>
</div>
)}
</>
);
}Workflow 2: Tracking Menu Analytics
const handleMenuSelect = (args) => {
// Track user interaction
trackEvent({
category: 'Menu',
action: 'Item Selected',
label: args.item.text,
parent: args.parentItem?.text,
timestamp: new Date().toISOString()
});
};
const handleBeforeOpen = (args) => {
// Track menu openings
trackEvent({
category: 'Menu',
action: 'Menu Opened',
label: args.item.text,
timestamp: new Date().toISOString()
});
};Workflow 3: Context-Aware Menu Behavior
const handleBeforeOpen = (args) => {
const userRole = getCurrentUserRole();
const context = getCurrentContext();
// Admin gets more options
if (args.item.text === 'Tools') {
if (userRole !== 'admin') {
args.item.items = args.item.items.filter(
item => !['User Management', 'System Settings'].includes(item.text)
);
}
}
// Disable options based on context
if (context === 'read-only') {
args.item.items.forEach(item => {
if (['Save', 'Delete', 'Edit'].includes(item.text)) {
item.disabled = true;
}
});
}
};Related Topics
- Menu Items Customization - Modify items
- Getting Started - Basic event setup
Getting Started with React Menu Component
Table of Contents
- Dependencies
- Development Environment Setup
- Installing Syncfusion Packages
- Adding Stylesheets
- Creating Your First Menu
- MenuItemModel Structure
- Rendering and Initialization
Dependencies
The Menu component requires the following packages:
@syncfusion/ej2-react-navigations
├── @syncfusion/ej2-react-base
├── @syncfusion/ej2-navigations
└── @syncfusion/ej2-baseThese dependencies handle the core navigation functionality, base UI utilities, and React integration.
Development Environment Setup
Using Vite (Recommended)
Vite provides faster development and smaller bundle sizes compared to create-react-app.
Create a new React application with JavaScript:
npm create vite@latest my-app -- --template react
cd my-app
npm run devCreate a new React application with TypeScript:
npm create vite@latest my-app -- --template react-ts
cd my-app
npm run devUsing create-react-app
Alternatively, you can use the traditional create-react-app setup:
npx create-react-app my-app
cd my-app
npm startInstalling Syncfusion Packages
Install the Menu component and its dependencies:
npm install @syncfusion/ej2-react-navigations --saveThis command automatically installs all required peer dependencies.
Adding Stylesheets
Add the Menu component's CSS imports to your main App.css file. Include styles for all required Syncfusion dependencies:
/* Base styles */
@import "../node_modules/@syncfusion/ej2-base/styles/tailwind3.css";
/* Button styles (used by Menu) */
@import "../node_modules/@syncfusion/ej2-buttons/styles/tailwind3.css";
/* Popup styles (for sub-menus) */
@import "../node_modules/@syncfusion/ej2-popups/styles/tailwind3.css";
/* Navigation and Menu styles */
@import "../node_modules/@syncfusion/ej2-navigations/styles/tailwind3.css";Available themes:
tailwind3.css(default)bootstrap5.3.cssfluent2.cssmaterial3.css
Choose the theme that matches your design requirements and replace tailwind3 accordingly.
Creating Your First Menu
Basic Menu with MenuItemModel
Create a functional component with a simple menu structure:
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import './App.css';
function App() {
// Define menu items
let menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ text: 'Close' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
},
{
text: 'View',
items: [
{ text: 'Toolbar' },
{ text: 'Sidebar' }
]
},
{
text: 'Tools',
items: [
{ text: 'Options' },
{ text: 'Settings' }
]
},
{
text: 'Help'
}
];
return (
<div className="App">
<h1>Menu Component</h1>
<MenuComponent items={menuItems}></MenuComponent>
</div>
);
}
export default App;MenuItemModel Structure
MenuItemModel defines the properties for each menu item:
interface MenuItemModel {
// Text displayed for the menu item
text?: string;
// Array of sub-menu items (creates hierarchical menus)
items?: MenuItemModel[];
// CSS ID for the item element
id?: string;
// URL for navigation links
url?: string;
// Icon CSS class (e.g., 'e-icons e-cut')
iconCss?: string;
// Icon for selected state
iconCss?: string;
// HTML attributes (data-*, aria-*, etc.)
htmlAttributes?: { [key: string]: string };
// Separator line between items
separator?: boolean;
// Disable the menu item
disabled?: boolean;
// Hide the menu item
hidden?: boolean;
}Practical Examples
Menu with icons:
const menuItems: MenuItemModel[] = [
{
text: 'File',
iconCss: 'e-icons e-file',
items: [
{ text: 'New', iconCss: 'e-icons e-new' },
{ text: 'Open', iconCss: 'e-icons e-open' },
{ separator: true },
{ text: 'Exit', iconCss: 'e-icons e-exit' }
]
}
];Menu with separators:
const menuItems: MenuItemModel[] = [
{ text: 'File' },
{ text: 'Edit' },
{ separator: true },
{ text: 'Help' }
];Menu with mixed items:
const menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ separator: true },
{ text: 'Recent Files' },
{ separator: true },
{ text: 'Exit' }
]
}
];Rendering and Initialization
Enable Ripple Effect (Optional)
For Material Design ripple effects on menu items:
import { enableRipple } from '@syncfusion/ej2-base';
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
enableRipple(true);
function App() {
// Component code...
}Complete Application Example
import { enableRipple } from '@syncfusion/ej2-base';
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import './App.css';
enableRipple(true);
function App() {
const menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ separator: true },
{ text: 'Exit' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
return (
<div className="App">
<MenuComponent items={menuItems}></MenuComponent>
</div>
);
}
export default App;Styling the Menu Container
Add CSS to style the menu wrapper:
.App {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* Menu container styling */
.e-menu {
background-color: #f5f5f5;
border: 1px solid #ddd;
border-radius: 4px;
}
/* Menu item hover state */
.e-menu-item:hover {
background-color: #e0e0e0;
}Next Steps
- Read data-binding.md to populate menus from JSON data sources
- Read events-and-interactions.md to respond to menu item clicks
- Read menu-items-customization.md to dynamically add/remove items
Hamburger and Mobile Mode
Table of Contents
1. Overview 2. Basic Hamburger Setup 3. Hamburger Properties 4. Programmatic Control 5. Mobile Responsive Patterns 6. Integration with Sidebar 7. Styling and Customization 8. Complete Examples
Overview
Hamburger mode is a mobile-first navigation pattern where the menu collapses into a hamburger icon (☰) on smaller screens. MenuComponent provides built-in support for this pattern through the hamburgerMode property.
When to use hamburger mode:
- Mobile and tablet applications
- Responsive web applications
- Space-constrained interfaces
- Progressive disclosure patterns
Basic Hamburger Setup
Simple Hamburger Menu
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
function App() {
const items: MenuItemModel[] = [
{ text: 'Home' },
{ text: 'About' },
{
text: 'Services',
items: [
{ text: 'Web Design' },
{ text: 'Development' },
{ text: 'Consulting' }
]
},
{ text: 'Contact' }
];
return (
<MenuComponent
items={items}
hamburgerMode={true}
title="Navigation Menu"
/>
);
}
export default App;With Responsive Header
function ResponsiveApp() {
const items = [
{ text: 'Home' },
{ text: 'Products' },
{ text: 'Services' },
{ text: 'Blog' },
{ text: 'Contact' }
];
return (
<div className="app">
<header className="navbar">
<div className="navbar-content">
<h1 className="logo">My App</h1>
<MenuComponent
items={items}
hamburgerMode={true}
title="Menu"
/>
</div>
</header>
<main>
{/* Main content */}
</main>
</div>
);
}
export default ResponsiveApp;Hamburger Properties
hamburgerMode Property
Type: boolean Default: false
// Disable hamburger mode
<MenuComponent items={items} hamburgerMode={false} />
// Enable hamburger mode
<MenuComponent items={items} hamburgerMode={true} />
// Enable based on screen size
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth < 768);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
<MenuComponent
items={items}
hamburgerMode={isMobile}
/>title Property
Type: string Default: undefined
// With title
<MenuComponent
items={items}
hamburgerMode={true}
title="Navigation"
/>
// Without title
<MenuComponent
items={items}
hamburgerMode={true}
/>
// Dynamic title
<MenuComponent
items={items}
hamburgerMode={true}
title={isOpen ? "Close Menu" : "Open Menu"}
/>target Property
Type: string (CSS selector) Default: undefined
// Target specific navbar element
<MenuComponent
items={items}
hamburgerMode={true}
target=".navbar"
/>
// Target by ID
<MenuComponent
items={items}
hamburgerMode={true}
target="#main-nav"
/>
// Target by class
<MenuComponent
items={items}
hamburgerMode={true}
target=".header-nav"
/>Programmatic Control
open() Method
Opens the hamburger menu programmatically.
import { useRef } from 'react';
function App() {
const menuRef = useRef(null);
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Contact' }
];
const openMenu = () => {
menuRef.current?.open();
};
return (
<>
<button onClick={openMenu}>Open Menu</button>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
/>
</>
);
}
export default App;close() Method
Closes the hamburger menu programmatically.
import { useRef } from 'react';
function App() {
const menuRef = useRef(null);
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Contact' }
];
const closeMenu = () => {
menuRef.current?.close();
};
const handleSelect = (args) => {
// Auto-close menu when item selected
closeMenu();
};
return (
<>
<button onClick={closeMenu}>Close Menu</button>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
select={handleSelect}
/>
</>
);
}
export default App;Toggle Menu
import { useRef, useState } from 'react';
function App() {
const menuRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Contact' }
];
const toggleMenu = () => {
if (isOpen) {
menuRef.current?.close();
setIsOpen(false);
} else {
menuRef.current?.open();
setIsOpen(true);
}
};
return (
<>
<button onClick={toggleMenu} className="toggle-btn">
{isOpen ? '✕' : '☰'}
</button>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
onOpen={() => setIsOpen(true)}
onClose={() => setIsOpen(false)}
/>
</>
);
}
export default App;Mobile Responsive Patterns
Responsive Breakpoint Handling
import { useEffect, useState } from 'react';
function ResponsiveMenu() {
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
const items = [
{ text: 'Home' },
{ text: 'Products' },
{ text: 'Services' },
{ text: 'Blog' },
{ text: 'Contact' }
];
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<MenuComponent
items={items}
hamburgerMode={isMobile}
orientation={isMobile ? 'Vertical' : 'Horizontal'}
/>
);
}
export default ResponsiveMenu;Multi-breakpoint Navigation
import { useEffect, useState } from 'react';
function MultiBreakpointNav() {
const [deviceType, setDeviceType] = useState('desktop');
const items = [
{ text: 'Home' },
{ text: 'Products' },
{ text: 'Services' },
{ text: 'Contact' }
];
useEffect(() => {
const handleResize = () => {
const width = window.innerWidth;
if (width < 640) {
setDeviceType('mobile');
} else if (width < 1024) {
setDeviceType('tablet');
} else {
setDeviceType('desktop');
}
};
window.addEventListener('resize', handleResize);
handleResize(); // Call once on mount
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<div className={`nav-${deviceType}`}>
{deviceType === 'mobile' && (
<MenuComponent
items={items}
hamburgerMode={true}
orientation="Vertical"
/>
)}
{deviceType !== 'mobile' && (
<MenuComponent
items={items}
hamburgerMode={false}
orientation="Horizontal"
/>
)}
</div>
);
}
export default MultiBreakpointNav;Integration with Sidebar
Complete Sidebar + Hamburger Integration
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { SidebarComponent } from '@syncfusion/ej2-react-popups';
import { useRef, useState } from 'react';
function SidebarApp() {
const sidebarRef = useRef(null);
const menuRef = useRef(null);
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
const items: MenuItemModel[] = [
{ text: 'Dashboard' },
{
text: 'Settings',
items: [
{ text: 'Profile' },
{ text: 'Account' },
{ text: 'Privacy' }
]
},
{ text: 'Help' },
{ text: 'Logout' }
];
const handleSelect = (args) => {
console.log('Selected:', args.item.text);
// In mobile, close sidebar after selection
if (isMobile) {
sidebarRef.current?.hide();
}
};
const toggleSidebar = () => {
sidebarRef.current?.toggle();
};
return (
<div className="app-container">
{/* Header */}
<div className="app-header">
<button
className="sidebar-toggle"
onClick={toggleSidebar}
>
☰
</button>
<h1>My Dashboard</h1>
</div>
{/* Sidebar with Menu */}
<SidebarComponent
ref={sidebarRef}
width="250px"
type="Push"
position="Left"
>
<MenuComponent
ref={menuRef}
items={items}
orientation="Vertical"
select={handleSelect}
hamburgerMode={false}
/>
</SidebarComponent>
{/* Main Content */}
<div className="app-content">
<h2>Welcome</h2>
<p>Main content goes here</p>
</div>
</div>
);
}
export default SidebarApp;Styling and Customization
Custom Hamburger Styling
/* CSS for hamburger menu styling */
.e-menu {
--menu-bg: #ffffff;
--menu-text: #333333;
--menu-hover-bg: #f0f0f0;
--menu-active-bg: #007bff;
}
.e-menu.hamburger-mode .e-menu-popup {
max-width: 300px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.e-menu.hamburger-mode .e-menu-item {
padding: 12px 16px;
border-bottom: 1px solid #e0e0e0;
}
.e-menu.hamburger-mode .e-menu-item:hover {
background-color: var(--menu-hover-bg);
}
.e-menu.hamburger-mode .e-menu-item.e-selected {
background-color: var(--menu-active-bg);
color: white;
}
/* Mobile-specific */
@media (max-width: 768px) {
.e-menu {
font-size: 16px; /* Prevents zoom on iOS */
}
.e-menu.hamburger-mode .e-menu-item {
padding: 16px;
font-size: 16px;
}
}Dynamic Theme Application
function ThemesHamburgerMenu() {
const [theme, setTheme] = useState('light');
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Contact' }
];
return (
<div className={`app theme-${theme}`}>
<button onClick={() => setTheme('light')}>Light</button>
<button onClick={() => setTheme('dark')}>Dark</button>
<MenuComponent
items={items}
hamburgerMode={true}
cssClass={`menu-${theme}`}
/>
</div>
);
}
export default ThemesHamburgerMenu;Complete Examples
Example 1: Simple Mobile Navigation
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
function MobileNav() {
const items = [
{ text: 'Home', iconCss: 'e-icons e-home' },
{ text: 'Shop', iconCss: 'e-icons e-shopping-cart' },
{ text: 'About', iconCss: 'e-icons e-info' },
{ text: 'Contact', iconCss: 'e-icons e-mail' }
];
return (
<div className="mobile-app">
<header>
<h1>Mobile Store</h1>
</header>
<MenuComponent
items={items}
hamburgerMode={true}
title="Menu"
orientation="Vertical"
/>
</div>
);
}
export default MobileNav;Example 2: Responsive Navigation with State Persistence
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import { useRef, useEffect } from 'react';
function PersistentMenu() {
const menuRef = useRef(null);
const items = [
{ text: 'Dashboard' },
{
text: 'Analytics',
items: [
{ text: 'Reports' },
{ text: 'Metrics' }
]
},
{ text: 'Users' },
{ text: 'Settings' }
];
// Restore menu state after component mounts
useEffect(() => {
const savedState = localStorage.getItem('menuOpen');
if (savedState === 'true') {
menuRef.current?.open();
}
}, []);
const handleOpen = () => {
localStorage.setItem('menuOpen', 'true');
};
const handleClose = () => {
localStorage.setItem('menuOpen', 'false');
};
return (
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
enablePersistence={true}
onOpen={handleOpen}
onClose={handleClose}
/>
);
}
export default PersistentMenu;Example 3: Full-Featured Responsive App
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import { useRef, useState, useEffect } from 'react';
function FullApp() {
const menuRef = useRef(null);
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
const [currentPage, setCurrentPage] = useState('home');
const items = [
{
text: 'Home',
select: () => setCurrentPage('home')
},
{
text: 'Products',
items: [
{ text: 'Electronics' },
{ text: 'Books' },
{ text: 'Clothing' }
],
select: () => setCurrentPage('products')
},
{
text: 'Account',
items: [
{ text: 'Profile' },
{ text: 'Orders' },
{ text: 'Logout' }
]
}
];
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth < 768);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
const handleItemSelect = (args) => {
if (isMobile) {
menuRef.current?.close();
}
};
return (
<div className="app">
<header className="app-header">
<h1>E-Store</h1>
</header>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={isMobile}
orientation={isMobile ? 'Vertical' : 'Horizontal'}
select={handleItemSelect}
title="Navigation"
/>
<main className="app-content">
{currentPage === 'home' && <h2>Welcome Home</h2>}
{currentPage === 'products' && <h2>Our Products</h2>}
</main>
</div>
);
}
export default FullApp;Best Practices
1. Always provide feedback - Show menu state (open/closed) visually 2. Close menu on selection - Improve UX by closing after navigation 3. Responsive breakpoints - Test at 375px, 768px, 1024px, 1280px 4. Touch-friendly - Ensure tap targets are at least 44×44px 5. Keyboard support - Ensure menu works with keyboard navigation 6. State persistence - Save menu state for better UX 7. Performance - Debounce resize events for smooth interaction
Related Topics
- Properties and Configuration - All properties
- Methods API - open() and close() methods
- Styling and Appearance - Custom styling
- Use Case Scenarios - Real-world examples
Menu Item Customization in React Menu Component
Table of Contents
- Adding Menu Items
- Removing Menu Items
- Enabling and Disabling Items
- Showing and Hiding Items
- Custom HTML Attributes
- Separator Support
- Practical Workflows
Adding Menu Items
Menu items can be dynamically added to the menu using the insertBefore() and insertAfter() methods on the MenuComponent instance.
insertAfter() Method
Adds items after a specified menu item:
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
let menuObj: MenuComponent;
const addAfterFile = () => {
// Insert new item after 'File' menu
menuObj.insertAfter(
[{ text: 'Recent Files' }], // Items to add
'File' // Target item to insert after
);
};
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' }
]
}
];
return (
<div>
<button onClick={addAfterFile}>Add Recent Files</button>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
></MenuComponent>
</div>
);
}
export default App;insertBefore() Method
Adds items before a specified menu item:
const addBeforeExit = () => {
// Insert separator and settings before Exit
menuObj.insertBefore(
[
{ separator: true },
{ text: 'Settings' }
],
'Exit' // Target item to insert before
);
};Adding Items to Sub-Menus
Insert items into nested sub-menus:
const addToSubmenu = () => {
// Add item to File sub-menu before 'Exit'
menuObj.insertBefore(
[{ text: 'Print' }],
'Exit' // Item in sub-menu
);
};
// For deeply nested items, use the full path or item reference
const dataSource = [
{
continent: 'Asia',
countries: [
{ country: 'China' },
{ country: 'India' },
{ country: 'Japan' }
]
},
{
continent: 'North America',
countries: [
{ country: 'Canada' },
{ country: 'USA' }
]
}
];
const addCountry = () => {
// Add country after India
menuObj.insertAfter(
[{ country: 'Thailand' }],
'India'
);
};Practical Example: Dynamic Menu Building
function App() {
let menuObj: MenuComponent;
const [itemCount, setItemCount] = React.useState(3);
const addDynamicItem = () => {
const newItem = { text: `New Item ${itemCount}` };
menuObj.insertAfter([newItem], 'Edit');
setItemCount(itemCount + 1);
};
const baseItems = [
{ text: 'File' },
{ text: 'Edit' },
{ text: 'View' }
];
return (
<div>
<button onClick={addDynamicItem}>Add Item</button>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={baseItems}
></MenuComponent>
</div>
);
}Removing Menu Items
Menu items can be removed using the removeItems() method:
const removeItems = () => {
// Remove single item by text
menuObj.removeItems(['Exit']);
// Remove multiple items
menuObj.removeItems(['South America', 'Mexico']);
};Complete Removal Example
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
let menuObj: MenuComponent;
const dataSource = [
{
continent: 'Asia',
countries: [
{ country: 'China' },
{ country: 'India' },
{ country: 'Japan' }
]
},
{
continent: 'North America',
countries: [
{ country: 'Canada' },
{ country: 'Mexico' },
{ country: 'USA' }
]
},
{
continent: 'South America',
countries: [
{ country: 'Brazil' },
{ country: 'Colombia' }
]
}
];
const removeCountries = () => {
// Remove specific items
menuObj.removeItems(['South America', 'Mexico']);
};
const fields = {
text: 'continent',
children: 'countries'
};
return (
<div>
<button onClick={removeCountries}>Remove Countries</button>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={dataSource}
fields={fields}
></MenuComponent>
</div>
);
}
export default App;Enabling and Disabling Items
Menu items can be enabled or disabled based on conditions or user interactions.
Disable Items Initially
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save', disabled: true }, // Disabled by default
{ text: 'Close', disabled: true }
]
}
];
<MenuComponent items={menuItems}></MenuComponent>Dynamic Enabling/Disabling
const handleItemSelect = (args) => {
// Disable certain items based on selection
if (args.item.text === 'New') {
// Find and disable 'Close' item
const closeItem = menuObj.element.querySelector('[data-text="Close"]');
if (closeItem) {
closeItem.disabled = true;
}
}
};Conditional Disabling with beforeOpen Event
function App() {
let menuObj: MenuComponent;
const handleBeforeOpen = (args) => {
// Check parent item to decide on child item state
if (args.parentItem?.text === 'File') {
// Disable Save if no document is open
if (!hasOpenDocument) {
args.items.forEach(item => {
if (item.text === 'Save') {
item.disabled = true;
}
});
}
}
};
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Save' },
{ text: 'Close' }
]
}
];
return (
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
beforeOpen={handleBeforeOpen}
></MenuComponent>
);
}Showing and Hiding Items
Control item visibility without removing them from the menu:
// Hide items initially
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Advanced Options', hidden: true } // Hidden initially
]
}
];
// Show/hide items dynamically
const toggleAdvancedOptions = () => {
const items = menuObj.items;
items.forEach(item => {
if (item.text === 'File') {
item.items.forEach(subItem => {
if (subItem.text === 'Advanced Options') {
subItem.hidden = !subItem.hidden;
}
});
}
});
menuObj.items = items; // Refresh menu
};Practical Example: Role-Based Menu Visibility
function App() {
let menuObj: MenuComponent;
const [userRole, setUserRole] = React.useState('viewer');
const baseItems = [
{
text: 'File',
items: [
{ text: 'New', hidden: userRole === 'viewer' },
{ text: 'Open' },
{ text: 'Delete', hidden: userRole !== 'admin' }
]
},
{
text: 'Tools',
items: [
{ text: 'Settings', hidden: userRole !== 'admin' },
{ text: 'Preferences' }
]
}
];
const promoteUser = () => {
setUserRole('admin');
};
return (
<div>
<button onClick={promoteUser}>Promote to Admin</button>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={baseItems}
></MenuComponent>
</div>
);
}Custom HTML Attributes
Add custom HTML attributes to menu items for additional functionality or styling:
const menuItems = [
{
text: 'File',
htmlAttributes: {
'data-role': 'menu-category',
'aria-label': 'File operations',
'data-toggle': 'tooltip',
'title': 'File management options'
},
items: [
{
text: 'Save',
htmlAttributes: {
'data-action': 'save-document',
'class': 'premium-feature',
'aria-describedby': 'save-help'
}
}
]
}
];
<MenuComponent items={menuItems}></MenuComponent>Custom Attributes for Styling
const menuItems = [
{
text: 'Export',
htmlAttributes: { 'class': 'export-item highlight' },
items: [
{ text: 'PDF', htmlAttributes: { 'class': 'format-pdf' } },
{ text: 'Excel', htmlAttributes: { 'class': 'format-excel' } },
{ text: 'CSV', htmlAttributes: { 'class': 'format-csv' } }
]
}
];
// CSS
const style = `
.export-item {
font-weight: bold;
}
.export-item.highlight {
color: #0066cc;
}
.format-pdf { color: #d41c1f; }
.format-excel { color: #1fa02b; }
.format-csv { color: #737373; }
`;Separator Support
Use separators to visually group related menu items:
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ separator: true }, // Visual separator
{ text: 'Recent Files' },
{ separator: true },
{ text: 'Exit' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' },
{ separator: true },
{ text: 'Select All' }
]
}
];
<MenuComponent items={menuItems}></MenuComponent>Practical Workflows
Workflow 1: Context Menu with Dynamic Items
function ContextMenu() {
let menuObj: MenuComponent;
const [selectedItem, setSelectedItem] = React.useState(null);
const showContextMenu = (e) => {
const items = [
{ text: `Selected: ${selectedItem}` },
{ separator: true },
{ text: 'Edit' },
{ text: 'Delete' },
{ text: 'Duplicate' }
];
setContextMenuItems(items);
};
return (
<div onContextMenu={showContextMenu}>
<MenuComponent
ref={(menu) => (menuObj = menu)}
items={menuItems}
></MenuComponent>
</div>
);
}Workflow 2: Dependent Menu Items
function DependentMenu() {
let menuObj: MenuComponent;
const [selectedFile, setSelectedFile] = React.useState(null);
const handleBeforeOpen = (args) => {
if (args.item.text === 'Edit' && !selectedFile) {
args.item.disabled = true; // Disable Edit if no file selected
}
};
return (
<MenuComponent
items={menuItems}
beforeOpen={handleBeforeOpen}
></MenuComponent>
);
}Workflow 3: Adding Submenu Items Dynamically
const addSubmenuItem = (parentText, newItem) => {
const items = menuObj.items;
// Find parent and add child
const parent = items.find(item => item.text === parentText);
if (parent) {
if (!parent.items) {
parent.items = [];
}
parent.items.push(newItem);
menuObj.items = items; // Refresh
}
};
// Usage
addSubmenuItem('File', { text: 'Import' });Related Topics
- Events and Interactions - Respond to item changes
- Getting Started - Basic menu setup
Methods API
Table of Contents
1. Item Manipulation 2. Item State Management 3. Item Access 4. Hamburger Control 5. Lifecycle
Item Manipulation
insertBefore()
Signature: insertBefore(items: MenuItemModel[], target: string | HTMLElement): void Description: Inserts menu items before a specified target item.
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
import { useRef } from 'react';
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'help', text: 'Help' }
];
const insertBeforeEdit = () => {
// Insert "Tools" menu before "Edit"
const newItems = [
{ id: 'tools', text: 'Tools' }
];
menuRef.current?.insertBefore(newItems, '#edit');
};
return (
<>
<button onClick={insertBeforeEdit}>Insert Before Edit</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;insertAfter()
Signature: insertAfter(items: MenuItemModel[], target: string | HTMLElement): void Description: Inserts menu items after a specified target item.
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'help', text: 'Help' }
];
const insertAfterEdit = () => {
// Insert "View" menu after "Edit"
const newItems = [
{
id: 'view',
text: 'View',
items: [
{ text: 'Zoom In' },
{ text: 'Zoom Out' }
]
}
];
menuRef.current?.insertAfter(newItems, '#edit');
};
return (
<>
<button onClick={insertAfterEdit}>Insert After Edit</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;removeItems()
Signature: removeItems(targets: string[] | HTMLElement[]): void Description: Removes menu items by their ID or element reference.
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'tools', text: 'Tools' },
{ id: 'help', text: 'Help' }
];
const removeTools = () => {
// Remove the "Tools" menu
menuRef.current?.removeItems(['#tools']);
};
const removeMultiple = () => {
// Remove multiple items
menuRef.current?.removeItems(['#tools', '#help']);
};
return (
<>
<button onClick={removeTools}>Remove Tools</button>
<button onClick={removeMultiple}>Remove Tools & Help</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;Item State Management
enableItems()
Signature: enableItems(targets: string[] | HTMLElement[], enable: boolean): void Description: Enables or disables menu items.
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'tools', text: 'Tools' }
];
const disableSave = () => {
// Disable the "Edit" menu
menuRef.current?.enableItems(['#edit'], false);
};
const enableAll = () => {
// Enable all items
menuRef.current?.enableItems(['#file', '#edit', '#tools'], true);
};
return (
<>
<button onClick={disableSave}>Disable Edit</button>
<button onClick={enableAll}>Enable All</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;showItems()
Signature: showItems(targets: string[] | HTMLElement[], show?: boolean): void Description: Shows hidden menu items.
function App() {
const menuRef = useRef(null);
const [hiddenItems, setHiddenItems] = useState(['#advanced', '#debug']);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'advanced', text: 'Advanced', style: { display: 'none' } }
];
const showAdvanced = () => {
// Show hidden "Advanced" menu
menuRef.current?.showItems(['#advanced']);
};
return (
<>
<button onClick={showAdvanced}>Show Advanced</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;hideItems()
Signature: hideItems(targets: string[] | HTMLElement[]): void Description: Hides visible menu items.
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'developer', text: 'Developer Tools' }
];
const hideDeveloperTools = () => {
// Hide the "Developer Tools" menu
menuRef.current?.hideItems(['#developer']);
};
return (
<>
<button onClick={hideDeveloperTools}>Hide Dev Tools</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;Item Access
setItem()
Signature: setItem(item: MenuItemModel, target: string | HTMLElement): void Description: Updates properties of an existing menu item.
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File', iconCss: 'e-icons e-folder' },
{ id: 'edit', text: 'Edit', iconCss: 'e-icons e-edit' }
];
const updateFile = () => {
// Update the "File" menu item
const updatedItem = {
id: 'file',
text: 'File (Updated)',
iconCss: 'e-icons e-folder-open'
};
menuRef.current?.setItem(updatedItem, '#file');
};
const addChildItems = () => {
// Add sub-items to File menu
const updatedItem = {
id: 'file',
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
};
menuRef.current?.setItem(updatedItem, '#file');
};
return (
<>
<button onClick={updateFile}>Update File Menu</button>
<button onClick={addChildItems}>Add File Sub-items</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;getItemIndex()
Signature: getItemIndex(target: string | HTMLElement): number Description: Returns the index of a menu item in the menu.
function App() {
const menuRef = useRef(null);
const items = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'view', text: 'View' },
{ id: 'help', text: 'Help' }
];
const logIndex = () => {
const index = menuRef.current?.getItemIndex('#edit');
console.log(`Edit menu index: ${index}`); // Output: 1
};
const getMultiple = () => {
const fileIndex = menuRef.current?.getItemIndex('#file');
const helpIndex = menuRef.current?.getItemIndex('#help');
console.log(`File: ${fileIndex}, Help: ${helpIndex}`); // Output: File: 0, Help: 3
};
return (
<>
<button onClick={logIndex}>Get Edit Index</button>
<button onClick={getMultiple}>Get Multiple Indices</button>
<MenuComponent
ref={menuRef}
items={items}
/>
</>
);
}
export default App;Hamburger Control
open()
Signature: open(): void Description: Opens the hamburger menu (in hamburgerMode).
function App() {
const menuRef = useRef(null);
const items = [
{ text: 'Home' },
{ text: 'About' },
{
text: 'Products',
items: [
{ text: 'Product 1' },
{ text: 'Product 2' }
]
},
{ text: 'Contact' }
];
const openMenu = () => {
menuRef.current?.open();
};
return (
<>
<button onClick={openMenu}>Open Menu</button>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
title="Navigation"
/>
</>
);
}
export default App;close()
Signature: close(): void Description: Closes the hamburger menu (in hamburgerMode).
function App() {
const menuRef = useRef(null);
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Products' },
{ text: 'Contact' }
];
const closeMenu = () => {
menuRef.current?.close();
};
const handleItemSelect = (args) => {
// Auto-close menu after item selection
closeMenu();
};
return (
<>
<button onClick={closeMenu}>Close Menu</button>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
select={handleItemSelect}
/>
</>
);
}
export default App;Responsive Example with open() and close():
function ResponsiveMenu() {
const menuRef = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Services' },
{ text: 'Contact' }
];
const toggleMenu = () => {
if (isOpen) {
menuRef.current?.close();
setIsOpen(false);
} else {
menuRef.current?.open();
setIsOpen(true);
}
};
const handleItemSelect = () => {
menuRef.current?.close();
setIsOpen(false);
};
return (
<>
<div className="navbar">
<h1>My App</h1>
<button
className="menu-toggle"
onClick={toggleMenu}
>
☰
</button>
</div>
<MenuComponent
ref={menuRef}
items={items}
hamburgerMode={true}
select={handleItemSelect}
/>
</>
);
}
export default ResponsiveMenu;Lifecycle
destroy()
Signature: destroy(): void Description: Destroys the menu component and cleans up resources.
import { useEffect } from 'react';
function App() {
const menuRef = useRef(null);
const items = [
{ text: 'File' },
{ text: 'Edit' },
{ text: 'Help' }
];
useEffect(() => {
// Cleanup on component unmount
return () => {
menuRef.current?.destroy();
};
}, []);
return (
<MenuComponent
ref={menuRef}
items={items}
/>
);
}
export default App;Complete Example: Dynamic Menu Management
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import { useRef, useState } from 'react';
function DynamicMenuApp() {
const menuRef = useRef(null);
const [logs, setLogs] = useState([]);
const baseItems = [
{ id: 'file', text: 'File' },
{ id: 'edit', text: 'Edit' },
{ id: 'view', text: 'View' },
{ id: 'help', text: 'Help' }
];
const addLog = (message) => {
setLogs(prev => [...prev, `[${new Date().toLocaleTimeString()}] ${message}`]);
};
const operations = {
insertAfter: () => {
menuRef.current?.insertAfter(
[{ id: 'tools', text: 'Tools' }],
'#view'
);
addLog('Inserted "Tools" after "View"');
},
removeEdit: () => {
menuRef.current?.removeItems(['#edit']);
addLog('Removed "Edit" menu');
},
disableView: () => {
menuRef.current?.enableItems(['#view'], false);
addLog('Disabled "View" menu');
},
enableAll: () => {
menuRef.current?.enableItems(['#file', '#edit', '#view', '#help'], true);
addLog('Enabled all menus');
},
updateHelp: () => {
menuRef.current?.setItem(
{
id: 'help',
text: 'Help & Support',
iconCss: 'e-icons e-question'
},
'#help'
);
addLog('Updated "Help" menu');
},
getFileIndex: () => {
const index = menuRef.current?.getItemIndex('#file');
addLog(`File menu index: ${index}`);
}
};
return (
<div className="container">
<h1>Dynamic Menu Management</h1>
<div className="operations">
{Object.entries(operations).map(([key, func]) => (
<button
key={key}
onClick={func}
className="op-btn"
>
{key.replace(/([A-Z])/g, ' $1').trim()}
</button>
))}
</div>
<div className="menu-container">
<MenuComponent
ref={menuRef}
items={baseItems}
/>
</div>
<div className="logs">
<h3>Operation Log</h3>
<ul>
{logs.map((log, idx) => (
<li key={idx}>{log}</li>
))}
</ul>
</div>
</div>
);
}
export default DynamicMenuApp;Related Topics
- Properties and Configuration - Available properties
- Events and Callbacks - Event handling
- Menu Items Customization - Item management examples
- Hamburger and Mobile Mode - Mobile implementation
Orientation and Layout in React Menu Component
Table of Contents
- Horizontal vs Vertical Orientation
- Changing Orientation
- Sub-Menu Positioning
- Horizontal Scrolling
- Vertical Scrolling
- Responsive Layout
- Practical Layout Patterns
Horizontal vs Vertical Orientation
The Menu component supports two primary orientations:
Vertical Orientation (Default)
Traditional dropdown menus where items stack vertically:
import { MenuComponent, MenuItemModel, Orientation } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
const menuItems: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
},
{
text: 'View'
}
];
// Vertical is default, explicit for clarity
return (
<MenuComponent
items={menuItems}
orientation={Orientation.Vertical}
></MenuComponent>
);
}
export default App;Horizontal Orientation
Menu items display horizontally in a row, typically used for top navigation bars:
import { Orientation } from '@syncfusion/ej2-react-navigations';
function App() {
return (
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
></MenuComponent>
);
}Changing Orientation
Orientation Property
interface MenuComponent {
orientation?: Orientation;
}
enum Orientation {
Vertical = 'Vertical',
Horizontal = 'Horizontal'
}Complete Horizontal Menu Example
import { MenuComponent, MenuItemModel, Orientation } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
import './App.css';
function App() {
const menuItems: MenuItemModel[] = [
{
text: 'Home',
url: '/'
},
{
text: 'Products',
items: [
{ text: 'Electronics' },
{ text: 'Clothing' },
{ text: 'Books' }
]
},
{
text: 'Services',
items: [
{ text: 'Consulting' },
{ text: 'Support' }
]
},
{
text: 'About Us'
},
{
text: 'Contact',
url: '/contact'
}
];
return (
<nav className="navbar">
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
></MenuComponent>
</nav>
);
}
// CSS
const styles = `
.navbar {
background-color: #333;
padding: 0;
}
.navbar .e-menu {
background-color: transparent;
border: none;
}
.navbar .e-menu-item {
color: white;
padding: 12px 20px;
}
.navbar .e-menu-item:hover {
background-color: #0066cc;
}
`;
export default App;Sub-Menu Positioning
Control where sub-menus appear relative to their parent items:
Vertical Sub-Menu Positions
For Vertical menus, sub-menus appear to the right or left:
import { MenuComponent, Orientation, SubMenuPosition } from '@syncfusion/ej2-react-navigations';
function App() {
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
}
];
// Sub-menu opens to the right (default)
return (
<MenuComponent
items={menuItems}
orientation={Orientation.Vertical}
// SubMenuPosition.RightBefore or RightAfter
></MenuComponent>
);
}Horizontal Sub-Menu Positions
For Horizontal menus, sub-menus appear above or below:
function App() {
// Sub-menu opens below parent (default)
return (
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
// Sub-menus drop down below the menu bar
></MenuComponent>
);
}Sub-Menu Positioning Behavior
const menuItems = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' },
{ text: 'Close' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
},
{
text: 'View',
items: [
{ text: 'Toolbars' },
{ text: 'Sidebar' },
{ text: 'Status Bar' }
]
}
];
// The menu automatically positions sub-menus to prevent viewport overflow
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
></MenuComponent>Horizontal Scrolling
Enable horizontal scrolling for menus with many items:
import { MenuComponent, HScrollSettings, HScroll } from '@syncfusion/ej2-react-navigations';
function App() {
// Many items requiring horizontal scroll
const menuItems = Array.from({ length: 50 }, (_, i) => ({
text: `Item ${i + 1}`,
id: `item-${i + 1}`
}));
const hScrollSettings: HScrollSettings = {
enable: true,
scrollStep: 100 // Pixels to scroll per arrow click
};
return (
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
hScroll={hScrollSettings}
></MenuComponent>
);
}HScrollSettings Configuration
interface HScrollSettings {
// Enable/disable horizontal scroll
enable?: boolean;
// Distance (in pixels) to scroll per arrow click
scrollStep?: number;
}
// Example with custom scroll step
const hScrollSettings: HScrollSettings = {
enable: true,
scrollStep: 200 // Scroll 200px per click
};Vertical Scrolling
Enable vertical scrolling for menus with many items:
import { MenuComponent, VScrollSettings } from '@syncfusion/ej2-react-navigations';
function App() {
// Many items in a sub-menu requiring vertical scroll
const menuItems = [
{
text: 'Countries',
items: Array.from({ length: 100 }, (_, i) => ({
text: `Country ${i + 1}`,
id: `country-${i + 1}`
}))
}
];
const vScrollSettings: VScrollSettings = {
enable: true,
scrollStep: 50,
scrollHeight: '300px' // Max height before scrolling
};
return (
<MenuComponent
items={menuItems}
vScroll={vScrollSettings}
></MenuComponent>
);
}VScrollSettings Configuration
interface VScrollSettings {
// Enable/disable vertical scroll
enable?: boolean;
// Distance (in pixels) to scroll per arrow click
scrollStep?: number;
// Maximum height of scrollable area
scrollHeight?: string; // e.g., '300px', '500px'
}
// Example with custom height
const vScrollSettings: VScrollSettings = {
enable: true,
scrollStep: 100,
scrollHeight: '250px'
};Practical Vertical Scroll Example
function App() {
const dataSource = [
{
category: 'Fruits',
items: [
{ fruit: 'Apple' },
{ fruit: 'Banana' },
{ fruit: 'Orange' },
{ fruit: 'Mango' },
{ fruit: 'Pineapple' },
{ fruit: 'Kiwi' },
{ fruit: 'Grape' },
{ fruit: 'Watermelon' },
{ fruit: 'Strawberry' },
{ fruit: 'Blueberry' }
]
}
];
const fields = {
text: 'category',
children: 'items'
};
const vScrollSettings: VScrollSettings = {
enable: true,
scrollHeight: '300px'
};
return (
<MenuComponent
items={dataSource}
fields={fields}
vScroll={vScrollSettings}
></MenuComponent>
);
}Responsive Layout
Adapt menu layout based on screen size:
Media Queries Approach
/* Desktop: Horizontal menu */
@media (min-width: 768px) {
.navbar .e-menu {
display: flex;
flex-direction: row;
}
.navbar .e-menu-item {
padding: 12px 20px;
border-right: 1px solid #ddd;
}
}
/* Mobile: Vertical menu (hamburger) */
@media (max-width: 768px) {
.navbar {
position: relative;
}
.navbar .e-menu {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
flex-direction: column;
background-color: #333;
z-index: 1000;
}
.navbar .e-menu.show {
display: flex;
}
.navbar .e-menu-item {
padding: 12px 16px;
border-bottom: 1px solid #555;
}
}JavaScript Responsive Menu
import { MenuComponent, Orientation } from '@syncfusion/ej2-react-navigations';
import * as React from 'react';
function App() {
const [isMobile, setIsMobile] = React.useState(window.innerWidth < 768);
React.useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
const menuItems = [
{ text: 'Home' },
{ text: 'Products', items: [{ text: 'Electronics' }, { text: 'Books' }] },
{ text: 'Services' },
{ text: 'Contact' }
];
return (
<MenuComponent
items={menuItems}
orientation={isMobile ? Orientation.Vertical : Orientation.Horizontal}
className={isMobile ? 'mobile-menu' : 'desktop-menu'}
></MenuComponent>
);
}
export default App;Practical Layout Patterns
Pattern 1: Top Navigation Bar with Responsive Hamburger
function App() {
const [showMenu, setShowMenu] = React.useState(false);
const [isMobile, setIsMobile] = React.useState(window.innerWidth < 768);
React.useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
const menuItems = [
{ text: 'Home', url: '/' },
{
text: 'Products',
items: [
{ text: 'Electronics' },
{ text: 'Clothing' }
]
},
{ text: 'Contact', url: '/contact' }
];
return (
<nav className="navbar">
{isMobile && (
<button
className="hamburger"
onClick={() => setShowMenu(!showMenu)}
>
☰
</button>
)}
<MenuComponent
items={menuItems}
orientation={isMobile ? Orientation.Vertical : Orientation.Horizontal}
className={isMobile && !showMenu ? 'hidden' : ''}
></MenuComponent>
</nav>
);
}
// CSS
const styles = `
.navbar {
background-color: #333;
display: flex;
align-items: center;
}
.hamburger {
display: none;
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
padding: 12px 16px;
}
@media (max-width: 768px) {
.hamburger {
display: block;
}
.navbar .e-menu.hidden {
display: none;
}
}
`;Pattern 2: Multi-Column Horizontal Menu
function App() {
const menuItems = [
{ text: 'Home' },
{
text: 'Products',
items: [
{ text: 'Category 1', items: [{ text: 'Item 1' }, { text: 'Item 2' }] },
{ text: 'Category 2', items: [{ text: 'Item 3' }, { text: 'Item 4' }] }
]
},
{ text: 'Services' }
];
return (
<MenuComponent
items={menuItems}
orientation={Orientation.Horizontal}
className="multi-column-menu"
></MenuComponent>
);
}
const styles = `
.multi-column-menu .e-submenu {
display: flex;
flex-wrap: wrap;
max-width: 600px;
}
.multi-column-menu .e-menu-item {
flex: 1 1 50%;
min-width: 150px;
}
`;Pattern 3: Vertical Sidebar Navigation
function SidebarMenu() {
const menuItems = [
{ text: 'Dashboard', iconCss: 'e-icons e-home' },
{ text: 'Users', iconCss: 'e-icons e-user-profile' },
{ text: 'Settings', iconCss: 'e-icons e-settings' },
{
text: 'Admin',
iconCss: 'e-icons e-lock',
items: [
{ text: 'System Settings' },
{ text: 'User Roles' },
{ text: 'Permissions' }
]
}
];
return (
<aside className="sidebar">
<MenuComponent
items={menuItems}
orientation={Orientation.Vertical}
className="sidebar-menu"
></MenuComponent>
</aside>
);
}
const styles = `
.sidebar {
width: 250px;
background-color: #2c3e50;
height: 100vh;
overflow-y: auto;
}
.sidebar-menu .e-menu {
border: none;
background-color: transparent;
}
.sidebar-menu .e-menu-item {
color: #ecf0f1;
padding: 12px 16px;
border-left: 3px solid transparent;
transition: all 0.3s;
}
.sidebar-menu .e-menu-item:hover {
background-color: #34495e;
border-left-color: #3498db;
}
`;Related Topics
- Getting Started - Basic setup
- Styling and Appearance - Styling options
Properties and Configuration
Table of Contents
1. Core Properties 2. Data Binding 3. Display and Layout 4. Interaction 5. Animation and Effects 6. Mobile and Responsive 7. State Management 8. Localization and Text 9. Security 10. Styling and Theming
Core Properties
items
Type: MenuItemModel[] Default: [] Description: Array of menu items to display in the menu component.
import { MenuComponent, MenuItemModel } from '@syncfusion/ej2-react-navigations';
function App() {
const items: MenuItemModel[] = [
{
text: 'File',
items: [
{ text: 'New' },
{ text: 'Open' },
{ text: 'Save' }
]
},
{
text: 'Edit',
items: [
{ text: 'Cut' },
{ text: 'Copy' },
{ text: 'Paste' }
]
}
];
return <MenuComponent items={items} />;
}
export default App;id
Type: string Default: undefined Description: Unique identifier for the menu element.
<MenuComponent id="main-menu" items={items} />template
Type: string | Function Default: undefined Description: Custom template for rendering menu items.
function customItemTemplate(item) {
return `<span class="custom-icon">${item.iconCss}</span>${item.text}`;
}
<MenuComponent
items={items}
template={customItemTemplate}
/>Data Binding
fields
Type: FieldSettingsModel Default: undefined Description: Specifies field mappings for data binding from external data sources.
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
function App() {
const data = [
{ Id: 1, Text: 'File', Childs: [
{ Id: 2, Text: 'New' },
{ Id: 3, Text: 'Open' }
] },
{ Id: 4, Text: 'Edit', Childs: [
{ Id: 5, Text: 'Cut' },
{ Id: 6, Text: 'Copy' }
] }
];
const fieldSettings = {
itemId: 'Id',
text: 'Text',
children: 'Childs'
};
return (
<MenuComponent
items={data}
fields={fieldSettings}
/>
);
}
export default App;FieldSettingsModel Properties:
itemId- Unique item identifier fieldtext- Item display text fieldiconCss- CSS class for iconsurl- Navigation URL fieldchildren- Child items fieldhtmlAttributes- HTML attributes fieldseparator- Separator fielddisabled- Disabled state field
Display and Layout
orientation
Type: Orientation ('Horizontal' | 'Vertical') Default: 'Horizontal' Description: Sets the orientation of the menu items.
// Horizontal menu (default)
<MenuComponent items={items} orientation="Horizontal" />
// Vertical menu
<MenuComponent items={items} orientation="Vertical" />enableScrolling
Type: boolean Default: true Description: Enables scrolling for menus with content exceeding viewport.
<MenuComponent
items={items}
enableScrolling={true}
/>
// With custom scroll settings
<MenuComponent
items={items}
enableScrolling={true}
vScroll={{ scrollStep: 5 }}
hScroll={{ scrollStep: 5 }}
/>cssClass
Type: string Default: undefined Description: Custom CSS classes to apply to the menu container.
<MenuComponent
items={items}
cssClass="custom-menu dark-theme"
/>title
Type: string Default: undefined Description: Title text displayed in hamburger mode.
<MenuComponent
items={items}
title="Menu"
/>Interaction
showItemOnClick
Type: boolean Default: false Description: When enabled, sub-menus open on item click instead of hover.
// Sub-menus open on hover (default)
<MenuComponent items={items} />
// Sub-menus open on click
<MenuComponent
items={items}
showItemOnClick={true}
/>hoverDelay
Type: number Default: 400 Description: Delay in milliseconds before sub-menu opens on hover.
// Default 400ms delay
<MenuComponent items={items} />
// Custom delay - 200ms
<MenuComponent
items={items}
hoverDelay={200}
/>
// No delay
<MenuComponent
items={items}
hoverDelay={0}
/>target
Type: string Default: undefined Description: CSS selector for the element where hamburger menu toggles are added.
<MenuComponent
items={items}
hamburgerMode={true}
target=".navbar"
/>Animation and Effects
animationSettings
Type: MenuAnimationSettings Default: { effect: 'SlideDown', duration: 400, easing: 'ease' } Description: Configures animation effects when sub-menus open and close.
const animationSettings = {
effect: 'SlideDown',
duration: 400,
easing: 'ease'
};
<MenuComponent
items={items}
animationSettings={animationSettings}
/>Available Effects:
None- No animationSlideDown- Slide down animationSlideUp- Slide up animationSlideLeft- Slide left animationSlideRight- Slide right animationFadeIn- Fade in animationFadeOut- Fade out animationZoomIn- Zoom in animationZoomOut- Zoom out animation
// Custom animation configuration
const customAnimation = {
effect: 'ZoomIn',
duration: 300,
easing: 'ease-in-out'
};
<MenuComponent
items={items}
animationSettings={customAnimation}
/>Mobile and Responsive
hamburgerMode
Type: boolean Default: false Description: Enables hamburger menu mode for mobile devices and responsive designs.
// Standard menu (default)
<MenuComponent items={items} />
// Hamburger mode for mobile
<MenuComponent
items={items}
hamburgerMode={true}
title="Navigation"
/>With Sidebar Integration:
import { MenuComponent } from '@syncfusion/ej2-react-navigations';
import { SidebarComponent } from '@syncfusion/ej2-react-popups';
function App() {
let sidebarInstance: SidebarComponent;
const handleHamburgerToggle = () => {
sidebarInstance.toggle();
};
const items = [
{ text: 'Home' },
{ text: 'About' },
{ text: 'Products' }
];
return (
<>
<div className="navbar">
<button onClick={handleHamburgerToggle}>☰</button>
<span>My Site</span>
</div>
<SidebarComponent
ref={(sidebar) => (sidebarInstance = sidebar)}
>
<MenuComponent
items={items}
hamburgerMode={true}
/>
</SidebarComponent>
</>
);
}
export default App;State Management
enablePersistence
Type: boolean Default: false Description: Enables state persistence to save expanded/collapsed menu state across page reloads.
// Without persistence (state lost on reload)
<MenuComponent items={items} />
// With persistence (state saved in localStorage)
<MenuComponent
items={items}
enablePersistence={true}
/>The menu state is stored in browser localStorage with key: {id}_menu
Localization and Text
locale
Type: string Default: 'en-US' Description: Culture/language identifier for localization.
// English (default)
<MenuComponent items={items} locale="en-US" />
// Spanish
<MenuComponent items={items} locale="es-ES" />
// German
<MenuComponent items={items} locale="de-DE" />
// Arabic (RTL)
<MenuComponent items={items} locale="ar-AE" enableRtl={true} />Security
enableHtmlSanitizer
Type: boolean Default: true Description: When enabled, sanitizes HTML content in menu items to prevent XSS attacks.
// With sanitization enabled (recommended for user-provided content)
const items = [
{ text: '<strong>File</strong>' }
];
<MenuComponent
items={items}
enableHtmlSanitizer={true}
/>
// Disable sanitization only if content is trusted
<MenuComponent
items={items}
enableHtmlSanitizer={false}
/>Styling and Theming
enableRtl
Type: boolean Default: false Description: Enables right-to-left text direction support.
// LTR layout (default)
<MenuComponent items={items} />
// RTL layout for Arabic, Hebrew, etc.
<MenuComponent
items={items}
enableRtl={true}
/>Full RTL Example:
function App() {
const items = [
{
text: 'ملف',
items: [
{ text: 'جديد' },
{ text: 'فتح' },
{ text: 'حفظ' }
]
},
{
text: 'تحرير',
items: [
{ text: 'قص' },
{ text: 'نسخ' },
{ text: 'لصق' }
]
}
];
return (
<MenuComponent
items={items}
enableRtl={true}
locale="ar-AE"
/>
);
}
export default App;MenuItemModel Properties
Individual menu items support these properties:
| Property | Type | Purpose |
|---|---|---|
text | string | Display text for the item |
iconCss | string | CSS class for item icon |
url | string | Navigation URL |
items | MenuItemModel[] | Child menu items |
disabled | boolean | Disable the item |
separator | boolean | Render as separator |
htmlAttributes | Object | Custom HTML attributes |
id | string | Unique item identifier |
Complete MenuItem Example:
const items = [
{
id: 'file',
text: 'File',
iconCss: 'e-icons e-folder-open',
items: [
{
id: 'new',
text: 'New',
iconCss: 'e-icons e-new'
},
{
id: 'open',
text: 'Open',
iconCss: 'e-icons e-open',
url: '/open'
},
{
separator: true
},
{
id: 'exit',
text: 'Exit',
disabled: false
}
]
}
];
<MenuComponent items={items} />Animation Settings Reference
const animationSettings = {
// Animation effect type
effect: 'SlideDown', // 'None', 'SlideDown', 'SlideUp', 'FadeIn', 'ZoomIn', etc.
// Duration in milliseconds
duration: 400,
// Easing function
easing: 'ease', // 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear'
// Delay before animation starts
delay: 0
};
<MenuComponent
items={items}
animationSettings={animationSettings}
/>Related Topics
- Methods and API - Available methods
- Events and Callbacks - Event handling
- Data Binding - Binding from data sources
- Styling and Appearance - Custom styling
- Hamburger and Mobile Mode - Mobile implementation