AdminMenu

The AdminMenu component provides a customizable, multi-level menu based on MUI RichTreeView, with support for icons, favorites, and connecting lines.

Usage

() => {
const { useState } = React;
const initialItems = [
{
id: 'client-list',
label: 'Client List',
icon: <DotPoints />,
path: '/client-list',
description: 'View and manage all client accounts',
},
{
id: 'client-management',
label: 'Client Management',
icon: <Settings3 />,
path: '/client-management',
description: 'Configure client settings and preferences',
},
{
id: 'finance-international',
label: 'Finance & International',
icon: <PiggyBank2 />,
path: '/finance-international',
description: 'Manage budgets and finances',
},
{
id: 'admin-management',
label: 'Admin Management',
icon: <UserCircle />,
path: '/admin-management',
description: 'Manage users and permissions',
},
{
id: 'redemption',
label: 'Redemption & Catalog',
icon: <ShoppingCart />,
path: '/redemption',
description: 'Redeem and browse catalog',
},
{
id: 'program',
label: 'Recognition Programs',
icon: <Tools />,
path: '/programs',
description: 'Configure programs',
},
{
id: 'reporting-analytics',
label: 'Reporting & Analytics',
icon: <BarChart2 />,
description: 'Access reports, dashboards, and analytics',
children: [
{
id: 'dashboards',
label: 'Dashboards',
path: '/reporting-analytics/dashboards',
description: 'View interactive dashboards',
},
{
id: 'reporting',
label: 'Reporting',
path: '/reporting-analytics/reporting',
description: 'Generate and customize reports',
children: [
{
id: 'bank-accounts',
label: 'Bank Accounts',
path: '/reporting-analytics/reporting/accounts',
description: 'Manage bank accounts',
},
{
id: 'payment-methods',
label: 'Payment Methods',
path: '/reporting-analytics/reporting/payment-methods',
description: 'Set up payment methods',
},
{
id: 'transaction-history',
label: 'Transaction History',
path: '/reporting-analytics/reporting/transactions',
description: 'View transaction history',
}
]
},
{
id: 'account-details',
label: 'Account Details',
path: '/reporting-analytics/account-details',
description: 'Monitor account information',
},
],
},
{
id: 'integrations',
label: 'App Integrations',
icon: <GitBranch />,
path: '/integrations',
description: 'Connect integrations',
},
{
id: 'security',
label: 'Security & Compliance',
icon: <Shield />,
path: '/security',
description: 'Security settings',
},
{
id: 'system-settings',
label: 'System Settings',
icon: <Settings1 />,
path: '/system-settings',
description: 'System configuration',
},
];
const [activeId, setActiveId] = useState('client-list');
const [favoriteIds, setFavoriteIds] = useState(['dashboards', 'transaction-history']);
const handleNavigate = (path, id) => {
setActiveId(id);
};
const handleToggleFavorite = (id, isFavorite) => {
if (!isFavorite) {
setFavoriteIds(prev => [...prev, id]);
console.log('added to favorites');
} else {
setFavoriteIds(prev => prev.filter(favId => favId !== id));
console.log('removed from favorites');
}
};
return (
<Box sx={{ width: 256, outline: '1px solid #E1E1EB', outlineOffset: '2px' }}>
<AdminMenu
items={initialItems}
activeId={activeId}
onNavigate={handleNavigate}
favoriteIds={favoriteIds}
onToggleFavorite={handleToggleFavorite}
maxDepth={2}
/>
</Box>
);
}

Props

PropTypeDefaultDescription
itemsMenuItemData[]Array of menu items to display. Supports nested children for sub-menus.
activeIdstringThe id of the currently selected menu item.
onNavigate(path: string, id: string) => voidCallback fired when a menu item is selected.
favoriteIdsstring[]Array of ids for favorite items (controlled favorites).
onToggleFavorite(id: string, isFavorite: boolean) => voidCallback fired when a favorite is toggled (controlled favorites).
maxDepthnumber2Maximum depth of nested menu items to render.
itemsExpandedstring[][]Array of item ids that should be expanded. Useful for controlling which menu sections are open.

Example

() => {
const { useState } = React;
// Simple icons for demo
const Folder = () => <span style={{fontWeight: 700, fontSize: 18}}>📁</span>;
const File = () => <span style={{fontWeight: 700, fontSize: 18}}>📄</span>;
const items = [
{
id: 'root',
label: 'Root',
icon: <Folder />,
description: 'Root folder',
children: [
{
id: 'level-1a',
label: 'Level 1A',
icon: <Folder />,
description: 'First child',
children: [
{
id: 'level-2a',
label: 'Level 2A',
icon: <Folder />,
description: 'Second level',
children: [
{
id: 'level-3a',
label: 'Level 3A',
icon: <File />,
description: 'Third level file',
},
{
id: 'level-3b',
label: 'Level 3B',
icon: <File />,
description: 'Another file',
}
]
},
{
id: 'level-2b',
label: 'Level 2B',
icon: <File />,
description: 'Second level file',
}
]
},
{
id: 'level-1b',
label: 'Level 1B',
icon: <Folder />,
description: 'Another first child',
children: [
{
id: 'level-2c',
label: 'Level 2C',
icon: <File />,
description: 'Second level file',
}
]
}
]
},
{
id: 'standalone',
label: 'Standalone',
icon: <File />,
description: 'No children',
}
];
const [activeId, setActiveId] = useState('level-3a');
const [favoriteIds, setFavoriteIds] = useState(['standalone']);
return (
<div style={{ width: 320, border: '1px solid #E1E1EB', borderRadius: 8 }}>
<AdminMenu
items={items}
activeId={activeId}
onNavigate={(_, id) => setActiveId(id)}
favoriteIds={favoriteIds}
onToggleFavorite={(id, isFav) =>
setFavoriteIds(favs =>
isFav ? favs.filter(f => f !== id) : [...favs, id]
)
}
maxDepth={2}
itemsExpanded={['root', 'level-1a', 'level-2a']}
/>
</div>
);
}

Advanced Example with Controlled Expansion

This example demonstrates how to control menu expansion/collapse based on navigation and favorites

() => {
const { useState, useCallback, useMemo } = React;
const menuItems = [
{
id: 'client-list',
label: 'Client List',
icon: <DotPoints />,
path: '/client-list',
description: 'View and manage all client accounts',
},
{
id: 'client-management',
label: 'Client Management',
icon: <Settings3 />,
path: '/client-management',
description: 'Configure client settings and preferences',
},
{
id: 'finance-international',
label: 'Finance & International',
icon: <PiggyBank2 />,
path: '/finance-international',
description: 'Manage budgets and finances',
},
{
id: 'admin-management',
label: 'Admin Management',
icon: <UserCircle />,
path: '/admin-management',
description: 'Manage users and permissions',
},
{
id: 'redemption',
label: 'Redemption & Catalog',
icon: <ShoppingCart />,
path: '/redemption',
description: 'Redeem and browse catalog',
},
{
id: 'program',
label: 'Recognition Programs',
icon: <Tools />,
path: '/programs',
description: 'Configure programs',
},
{
id: 'reporting-analytics',
label: 'Reporting & Analytics',
icon: <BarChart2 />,
description: 'Access reports, dashboards, and analytics',
children: [
{
id: 'dashboards',
label: 'Dashboards',
path: '/reporting-analytics/dashboards',
description: 'View interactive dashboards',
},
{
id: 'reporting',
label: 'Reporting',
path: '/reporting-analytics/reporting',
description: 'Generate and customize reports',
children: [
{
id: 'bank-accounts',
label: 'Bank Accounts',
path: '/reporting-analytics/reporting/accounts',
description: 'Manage bank accounts',
},
{
id: 'payment-methods',
label: 'Payment Methods',
path: '/reporting-analytics/reporting/payment-methods',
description: 'Set up payment methods',
},
{
id: 'transaction-history',
label: 'Transaction History',
path: '/reporting-analytics/reporting/transactions',
description: 'View transaction history',
}
]
},
{
id: 'account-details',
label: 'Account Details',
path: '/reporting-analytics/account-details',
description: 'Monitor account information',
},
],
},
{
id: 'integrations',
label: 'App Integrations',
icon: <GitBranch />,
path: '/integrations',
description: 'Connect integrations',
},
{
id: 'security',
label: 'Security & Compliance',
icon: <Shield />,
path: '/security',
description: 'Security settings',
},
{
id: 'system-settings',
label: 'System Settings',
icon: <Settings1 />,
path: '/system-settings',
description: 'System configuration',
},
];
const [activeId, setActiveId] = useState('dashboard');
const [favoriteIds, setFavoriteIds] = useState(['user-analytics', 'financial-reports']);
const [expandedItems, setExpandedItems] = useState(['reports', 'analytics']); // Start with some items expanded
// Helper function to get parent chain for an item
const getParentChain = useCallback((targetId, items) => {
const findParents = (currentItems, id, ancestors = []) => {
for (const item of currentItems) {
if (item.id === id) return ancestors;
if (item.children) {
const result = findParents(item.children, id, [...ancestors, item.id]);
if (result) return result;
}
}
return null;
};
return findParents(items, targetId) || [];
}, []);
// Helper function to check if an item has children (is expandable)
const hasChildren = useCallback((itemId, items) => {
const findItem = (currentItems, id) => {
for (const item of currentItems) {
if (item.id === id) return item;
if (item.children) {
const found = findItem(item.children, id);
if (found) return found;
}
}
return null;
};
const item = findItem(items, itemId);
return item?.children && item.children.length > 0;
}, []);
// Expand to show the active item and collapse others
const expandToItem = useCallback((itemId) => {
const parentChain = getParentChain(itemId, menuItems);
// If the clicked item has children, include it in expanded items
if (hasChildren(itemId, menuItems)) {
setExpandedItems([...parentChain, itemId]);
} else {
// If it's a leaf item or standalone item, set to parent chain
// When parent chain is empty (standalone items), this collapses everything
setExpandedItems(parentChain.length > 0 ? parentChain : ['non-child']);
}
}, [getParentChain, hasChildren, menuItems]);
const handleNavigate = useCallback((path, itemId) => {
console.log(`Navigating to: ${path} (${itemId})`);
setActiveId(itemId);
// Always update expansion state to show only relevant items
expandToItem(itemId);
}, [expandToItem]);
const handleToggleFavorite = useCallback((id, isFavorite) => {
if (!isFavorite) {
// Adding to favorites - maintain current active item's expansion state
setFavoriteIds(prev => [...prev, id]);
// Only expand to show the currently active item, not the favorited item
if (activeId) {
expandToItem(activeId);
}
console.log(`Added "${id}" to favorites`);
} else {
// Removing from favorites - keep current expansion state
setFavoriteIds(prev => prev.filter(favId => favId !== id));
console.log(`Removed "${id}" from favorites`);
}
}, [activeId, expandToItem]);
// Show current state for demo purposes
const currentState = useMemo(() => ({
activeId,
favoriteIds,
expandedItems
}), [activeId, favoriteIds, expandedItems]);
return (
<div style={{ display: 'flex', gap: '20px' }}>
<div style={{ width: 320, border: '1px solid #E1E1EB', borderRadius: 8 }}>
<AdminMenu
items={menuItems}
activeId={activeId}
onNavigate={handleNavigate}
favoriteIds={favoriteIds}
onToggleFavorite={handleToggleFavorite}
maxDepth={3}
itemsExpanded={expandedItems}
/>
</div>
</div>
);
}