mantine-contextmenu is a powerful library for creating context menus (right-click menus) in React applications using Mantine UI components. It provides a flexible API for displaying contextual actions, submenus, and custom content when users right-click on elements. This guide walks through advanced usage of mantine-contextmenu with React and Mantine, including custom configurations, nested menus, and complex interaction patterns. This is part 45 of a series on using mantine-contextmenu with React.
Prerequisites
Before you begin, make sure you have:
- Node.js version 14.0 or higher installed
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) or create-react-app setup
- Mantine UI installed and configured
- Basic knowledge of React hooks (useState, useCallback)
- Familiarity with Mantine UI components
- Understanding of JavaScript/TypeScript
Installation
Install mantine-contextmenu and Mantine dependencies:
npm install mantine-contextmenu @mantine/core @mantine/hooks
Or with yarn:
yarn add mantine-contextmenu @mantine/core @mantine/hooks
Or with pnpm:
pnpm add mantine-contextmenu @mantine/core @mantine/hooks
After installation, your package.json should include:
{
"dependencies": {
"mantine-contextmenu": "^1.0.0",
"@mantine/core": "^6.0.0",
"@mantine/hooks": "^6.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
Set up Mantine provider and context menu provider in your main entry file:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { MantineProvider } from '@mantine/core';
import { ContextMenuProvider } from 'mantine-contextmenu';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<MantineProvider>
<ContextMenuProvider>
<App />
</ContextMenuProvider>
</MantineProvider>
</React.StrictMode>
);
First Example / Basic Usage
Let's create a simple context menu. Create a new file src/ContextMenuExample.jsx:
// src/ContextMenuExample.jsx
import React from 'react';
import { useContextMenu } from 'mantine-contextmenu';
import { Box, Button } from '@mantine/core';
function ContextMenuExample() {
const showContextMenu = useContextMenu();
const handleRightClick = (event) => {
showContextMenu({
event,
items: [
{
key: 'copy',
label: 'Copy',
onClick: () => {
console.log('Copy clicked');
alert('Copied!');
}
},
{
key: 'paste',
label: 'Paste',
onClick: () => {
console.log('Paste clicked');
alert('Pasted!');
}
},
{
key: 'delete',
label: 'Delete',
onClick: () => {
console.log('Delete clicked');
alert('Deleted!');
},
color: 'red'
}
]
});
};
return (
<Box p="xl">
<h2>Context Menu Example</h2>
<Box
onContextMenu={handleRightClick}
p="md"
style={{
border: '2px dashed #ddd',
borderRadius: '8px',
cursor: 'context-menu',
minHeight: '200px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Right-click here to open context menu
</Box>
</Box>
);
}
export default ContextMenuExample;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import ContextMenuExample from './ContextMenuExample';
import './App.css';
function App() {
return (
<div className="App">
<ContextMenuExample />
</div>
);
}
export default App;
Understanding the Basics
mantine-contextmenu provides several key features:
- useContextMenu hook: Hook to access context menu functionality
- showContextMenu function: Displays the context menu at the specified position
- Menu items: Array of items with labels, icons, and actions
- Submenus: Nested menu items for complex hierarchies
- Custom content: Support for custom React components in menus
- Mantine integration: Seamless integration with Mantine UI components
Key concepts for advanced usage:
-
Event handling: Use
onContextMenuto capture right-click events - Menu configuration: Configure items, positioning, and behavior
- Submenus: Create nested menu structures
- Custom rendering: Use custom components for menu items
- State management: Manage menu state and item states
Here's an example with submenus and icons:
// src/AdvancedContextMenuExample.jsx
import React from 'react';
import { useContextMenu } from 'mantine-contextmenu';
import { Box, Button } from '@mantine/core';
import { IconCopy, IconCut, IconPaste, IconTrash, IconEdit } from '@tabler/icons-react';
function AdvancedContextMenuExample() {
const showContextMenu = useContextMenu();
const handleRightClick = (event) => {
showContextMenu({
event,
items: [
{
key: 'edit',
label: 'Edit',
icon: <IconEdit size={16} />,
onClick: () => alert('Edit clicked')
},
{
key: 'copy',
label: 'Copy',
icon: <IconCopy size={16} />,
onClick: () => alert('Copy clicked')
},
{
key: 'cut',
label: 'Cut',
icon: <IconCut size={16} />,
onClick: () => alert('Cut clicked')
},
{
key: 'paste',
label: 'Paste',
icon: <IconPaste size={16} />,
onClick: () => alert('Paste clicked')
},
{
key: 'divider',
type: 'divider'
},
{
key: 'delete',
label: 'Delete',
icon: <IconTrash size={16} />,
color: 'red',
onClick: () => alert('Delete clicked')
},
{
key: 'more',
label: 'More',
children: [
{
key: 'rename',
label: 'Rename',
onClick: () => alert('Rename clicked')
},
{
key: 'duplicate',
label: 'Duplicate',
onClick: () => alert('Duplicate clicked')
}
]
}
]
});
};
return (
<Box p="xl">
<h2>Advanced Context Menu</h2>
<Box
onContextMenu={handleRightClick}
p="md"
style={{
border: '2px dashed #ddd',
borderRadius: '8px',
cursor: 'context-menu',
minHeight: '200px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Right-click here for advanced menu with submenus
</Box>
</Box>
);
}
export default AdvancedContextMenuExample;
Practical Example / Building Something Real
Let's build a file manager with context menus:
// src/FileManagerWithContextMenu.jsx
import React, { useState } from 'react';
import { useContextMenu } from 'mantine-contextmenu';
import { Box, Paper, Text, Group, ActionIcon } from '@mantine/core';
import { IconFolder, IconFile, IconEdit, IconTrash, IconCopy, IconCut, IconPaste } from '@tabler/icons-react';
function FileManagerWithContextMenu() {
const showContextMenu = useContextMenu();
const [files, setFiles] = useState([
{ id: 1, name: 'Documents', type: 'folder' },
{ id: 2, name: 'Images', type: 'folder' },
{ id: 3, name: 'report.pdf', type: 'file' },
{ id: 4, name: 'photo.jpg', type: 'file' },
{ id: 5, name: 'notes.txt', type: 'file' }
]);
const [selectedFile, setSelectedFile] = useState(null);
const handleFileRightClick = (event, file) => {
event.preventDefault();
setSelectedFile(file);
const menuItems = [
{
key: 'open',
label: 'Open',
onClick: () => {
alert(`Opening ${file.name}`);
}
},
{
key: 'edit',
label: 'Edit',
icon: <IconEdit size={16} />,
onClick: () => {
alert(`Editing ${file.name}`);
}
},
{
key: 'divider1',
type: 'divider'
},
{
key: 'copy',
label: 'Copy',
icon: <IconCopy size={16} />,
onClick: () => {
alert(`Copied ${file.name}`);
}
},
{
key: 'cut',
label: 'Cut',
icon: <IconCut size={16} />,
onClick: () => {
alert(`Cut ${file.name}`);
}
},
{
key: 'paste',
label: 'Paste',
icon: <IconPaste size={16} />,
disabled: true,
onClick: () => {
alert('Paste clicked');
}
},
{
key: 'divider2',
type: 'divider'
},
{
key: 'rename',
label: 'Rename',
onClick: () => {
const newName = prompt('Enter new name:', file.name);
if (newName) {
setFiles(files.map(f =>
f.id === file.id ? { ...f, name: newName } : f
));
}
}
},
{
key: 'delete',
label: 'Delete',
icon: <IconTrash size={16} />,
color: 'red',
onClick: () => {
if (confirm(`Delete ${file.name}?`)) {
setFiles(files.filter(f => f.id !== file.id));
}
}
}
];
showContextMenu({
event,
items: menuItems
});
};
return (
<Box p="xl">
<h2>File Manager with Context Menu</h2>
<Box mt="md">
{files.map(file => (
<Paper
key={file.id}
p="md"
mb="sm"
onContextMenu={(e) => handleFileRightClick(e, file)}
style={{
cursor: 'context-menu',
border: selectedFile?.id === file.id ? '2px solid #007bff' : '1px solid #ddd',
borderRadius: '8px'
}}
>
<Group>
{file.type === 'folder' ? (
<IconFolder size={24} color="#ffc107" />
) : (
<IconFile size={24} color="#007bff" />
)}
<Text>{file.name}</Text>
</Group>
</Paper>
))}
</Box>
<Text size="sm" color="dimmed" mt="md">
Right-click on any file or folder to see the context menu
</Text>
</Box>
);
}
export default FileManagerWithContextMenu;
Now create a table with row context menus:
// src/TableWithContextMenu.jsx
import React, { useState } from 'react';
import { useContextMenu } from 'mantine-contextmenu';
import { Box, Table, Text, Badge } from '@mantine/core';
import { IconEdit, IconTrash, IconEye, IconDownload } from '@tabler/icons-react';
function TableWithContextMenu() {
const showContextMenu = useContextMenu();
const [users, setUsers] = useState([
{ id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User' }
]);
const handleRowRightClick = (event, user) => {
showContextMenu({
event,
items: [
{
key: 'view',
label: 'View Details',
icon: <IconEye size={16} />,
onClick: () => {
alert(`Viewing ${user.name}`);
}
},
{
key: 'edit',
label: 'Edit User',
icon: <IconEdit size={16} />,
onClick: () => {
alert(`Editing ${user.name}`);
}
},
{
key: 'download',
label: 'Download',
icon: <IconDownload size={16} />,
onClick: () => {
alert(`Downloading ${user.name}'s data`);
}
},
{
key: 'divider',
type: 'divider'
},
{
key: 'delete',
label: 'Delete User',
icon: <IconTrash size={16} />,
color: 'red',
onClick: () => {
if (confirm(`Delete ${user.name}?`)) {
setUsers(users.filter(u => u.id !== user.id));
}
}
}
]
});
};
return (
<Box p="xl">
<h2>Table with Context Menu</h2>
<Table mt="md" striped highlightOnHover>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Role</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr
key={user.id}
onContextMenu={(e) => handleRowRightClick(e, user)}
style={{ cursor: 'context-menu' }}
>
<td>{user.name}</td>
<td>{user.email}</td>
<td>
<Badge color={user.role === 'Admin' ? 'red' : 'blue'}>
{user.role}
</Badge>
</td>
</tr>
))}
</tbody>
</Table>
<Text size="sm" color="dimmed" mt="md">
Right-click on any row to see the context menu
</Text>
</Box>
);
}
export default TableWithContextMenu;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import FileManagerWithContextMenu from './FileManagerWithContextMenu';
import TableWithContextMenu from './TableWithContextMenu';
import './App.css';
function App() {
return (
<div className="App">
<FileManagerWithContextMenu />
<TableWithContextMenu />
</div>
);
}
export default App;
This example demonstrates:
- File manager with context menus
- Table rows with context menus
- Menu items with icons
- Submenus and dividers
- Dynamic menu items based on context
- State management for selected items
Common Issues / Troubleshooting
Context menu not appearing: Ensure
ContextMenuProviderwraps your app andMantineProvideris set up correctly. Also make sure you're callingshowContextMenuwith a valid event object.Menu positioning issues: The menu automatically positions itself based on the event coordinates. If it appears in the wrong place, check that you're passing the correct event object from
onContextMenu.Menu items not working: Ensure
onClickhandlers are properly defined. Check for JavaScript errors in the console that might prevent handlers from executing.Submenus not displaying: Make sure submenu items are defined in the
childrenproperty of a menu item. The structure should be:{ key: 'parent', label: 'Parent', children: [...] }.Styling conflicts: If the menu doesn't look right, check for CSS conflicts with Mantine styles. You can customize menu appearance using Mantine's theming system.
Event propagation: If the context menu appears but immediately disappears, you might need to call
event.preventDefault()in youronContextMenuhandler to prevent default browser behavior.
Next Steps
Now that you have an advanced understanding of mantine-contextmenu:
- Explore advanced menu configurations and theming
- Learn about custom menu item rendering
- Implement keyboard navigation for accessibility
- Add menu item states (disabled, loading, etc.)
- Integrate with Mantine's notification system
- Learn about other context menu libraries
- Check the official repository: https://github.com/icflorescu/mantine-contextmenu
- Look for part 46 of this series for more advanced topics
Summary
You've successfully integrated mantine-contextmenu into your React application with advanced features including file manager context menus, table row menus, submenus, and custom menu items. mantine-contextmenu provides a powerful, Mantine-integrated solution for creating context menus with extensive customization options.
SEO Keywords
mantine-contextmenu
React context menu
mantine-contextmenu tutorial
React right-click menu
mantine-contextmenu installation
React Mantine context menu
mantine-contextmenu example
React contextual menu
mantine-contextmenu setup
React menu library
mantine-contextmenu customization
React context menu hooks
mantine-contextmenu submenus
React Mantine UI
mantine-contextmenu getting started

Top comments (0)