Menu is a versatile component that provides various features such as inline and portal rendering, composite structures, app-style layouts, menubars, sidebars, and router integration.
import { Menu } from 'primereact/menu';<Menu>
<Menu.List>
<Menu.Label />
<Menu.Item />
<Menu.Separator />
<Menu.CheckboxItem>
<Menu.CheckboxIcon />
</Menu.CheckboxItem>
<Menu.RadioGroup>
<Menu.RadioItem>
<Menu.RadioIcon />
</Menu.RadioItem>
<Menu.RadioItem>
<Menu.RadioIcon />
</Menu.RadioItem>
</Menu.RadioGroup>
</Menu.List>
<Menu.Separator />
<Menu.Sub>
<Menu.Trigger>
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item />
<Menu.Separator />
<Menu.Item />
</Menu.List>
</Menu.Sub>
</Menu>The main Menu component groups menu items with Menu.List, adds individual menu elements with Menu.Item, uses separators with Menu.Separator, and creates submenus with Menu.Sub. Submenus are triggered by Menu.Trigger and can have their own Menu.List structure.
'use client';
import { Menu } from 'primereact/menu';
export default function InlineDemo() {
return (
<div className="flex justify-center">
<Menu className="w-64">
<Menu.List>
<Menu.Item>
<i className="pi pi-home" />
Dashboard
</Menu.Item>
<Menu.Separator />
<Menu.Label>Workspace</Menu.Label>
<Menu.Item>
<i className="pi pi-chart-line" />
Analytics
</Menu.Item>
<Menu.Sub defaultOpen={true}>
<Menu.Trigger>
<i className="pi pi-folder" />
Projects
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-briefcase" />
Active Projects
</Menu.Item>
<Menu.Item>
<i className="pi pi-clock" />
Recent
</Menu.Item>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-star" />
Favorites
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-code" />
Website Redesign
</Menu.Item>
<Menu.Item>
<i className="pi pi-mobile" />
Mobile App
</Menu.Item>
<Menu.Item>
<i className="pi pi-database" />
API Development
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Item>
<i className="pi pi-check-circle" />
Completed
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-users" />
Team
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-user-plus" />
Add Member
</Menu.Item>
<Menu.Item>
<i className="pi pi-sitemap" />
Organization
</Menu.Item>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-cog" />
Settings
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-shield" />
Permissions
</Menu.Item>
<Menu.Item>
<i className="pi pi-bell" />
Notifications
</Menu.Item>
<Menu.Item>
<i className="pi pi-lock" />
Privacy
</Menu.Item>
</Menu.List>
</Menu.Sub>
</Menu.List>
</Menu.Sub>
<Menu.Separator />
<Menu.Item>
<i className="pi pi-question-circle" />
Help & Support
</Menu.Item>
</Menu.List>
</Menu>
</div>
);
}
The composite prop allows combining multiple Menu components to create complex nested menus. Each Menu can have its own structure, and submenus can be nested within parent menus.
'use client';
import { Menu } from 'primereact/menu';
export default function CompositeDemo() {
return (
<div className="flex justify-center">
<Menu className="w-56" composite>
<Menu.List>
<Menu.Item>
<i className="pi pi-file" />
New
</Menu.Item>
<Menu.Item>
<i className="pi pi-folder-open" />
Open
</Menu.Item>
<Menu.Separator />
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-download" />
Import
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-file" />
From File
</Menu.Item>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-cloud" />
From Cloud
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>Google Drive</Menu.Item>
<Menu.Item>Dropbox</Menu.Item>
<Menu.Item>OneDrive</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Item>
<i className="pi pi-globe" />
From URL
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-share-alt" />
Share
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-send" />
Send via Email
</Menu.Item>
<Menu.Item>
<i className="pi pi-link" />
Copy Link
</Menu.Item>
<Menu.Item>
<i className="pi pi-users" />
Share with Team
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Item>
<i className="pi pi-save" />
Save
</Menu.Item>
<Menu.Separator />
<Menu.Item>
<i className="pi pi-sign-out" />
Exit
</Menu.Item>
</Menu.List>
</Menu>
</div>
);
}
Menu.Portal renders the menu content in a portal, positioning it outside the DOM hierarchy. This is useful for dropdown menus triggered by buttons or avatars, ensuring proper z-index stacking and avoiding overflow issues.
'use client';
import { Avatar } from 'primereact/avatar';
import { Menu } from 'primereact/menu';
export default function PortalDemo() {
return (
<div className="flex justify-center">
<Menu className="w-64">
<Menu.Trigger className="flex items-center gap-3">
<Avatar shape="circle">
<Avatar.Image src="https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png" />
<Avatar.Fallback>A</Avatar.Fallback>
</Avatar>
<div className="flex flex-col items-start">
<span className="font-semibold text-sm">Sarah Anderson</span>
<span className="text-xs">Product Manager</span>
</div>
</Menu.Trigger>
<Menu.Portal>
<Menu.List>
<Menu.Label className="flex-col items-start gap-2">
<p className="font-bold text-sm">Active Account</p>
<p className="font-bold text-sm">[email protected]</p>
</Menu.Label>
<Menu.Separator />
<Menu.Item>
<i className="pi pi-user" />
Profile Settings
</Menu.Item>
<Menu.Item>
<i className="pi pi-bell" />
Notifications
</Menu.Item>
<Menu.Item>
<i className="pi pi-bookmark" />
Saved Items
</Menu.Item>
<Menu.Item>
<i className="pi pi-shield" />
Privacy & Security
</Menu.Item>
<Menu.Item>
<i className="pi pi-palette" />
Appearance
</Menu.Item>
<Menu.Item disabled>
<i className="pi pi-history" />
Activity Log
<span className="ml-auto text-xs">Premium</span>
</Menu.Item>
<Menu.Separator />
<Menu.Item className="text-red-600">
<i className="pi pi-power-off" />
Sign Out
</Menu.Item>
</Menu.List>
</Menu.Portal>
</Menu>
</div>
);
}
The Menu component can be customized to create app launchers or grid-based menus. By applying custom classes to Menu.List and Menu.Item, the menu layout can be transformed into a grid structure with custom styling for icons and labels.
'use client';
import { Menu } from 'primereact/menu';
const apps = [
{ label: 'Search', icon: 'pi-search', gradient: 'from-sky-400 to-cyan-500' },
{ label: 'Maps', icon: 'pi-map-marker', gradient: 'from-emerald-500 to-green-600' },
{ label: 'Mail', icon: 'pi-envelope', gradient: 'from-orange-400 to-red-500' },
{ label: 'Drive', icon: 'pi-cloud', gradient: 'from-blue-500 to-indigo-600' },
{ label: 'Calendar', icon: 'pi-calendar', gradient: 'from-violet-500 to-purple-600' },
{ label: 'Photos', icon: 'pi-image', gradient: 'from-fuchsia-500 to-pink-600' },
{ label: 'Videos', icon: 'pi-video', gradient: 'from-red-500 to-rose-600' },
{ label: 'Analytics', icon: 'pi-chart-line', gradient: 'from-cyan-500 to-blue-600' },
{ label: 'Settings', icon: 'pi-cog', gradient: 'from-slate-500 to-zinc-700' }
];
export default function AppsDemo() {
return (
<div className="flex justify-center">
<Menu className="w-116">
<Menu.Trigger rounded iconOnly>
<i className="pi pi-bars" />
</Menu.Trigger>
<Menu.Portal>
<Menu.List className="grid grid-cols-3 gap-1 p-2">
{apps.map((app) => (
<Menu.Item key={app.label} className="flex-col items-center justify-center h-28 gap-3">
<div
className={`w-14 h-14 rounded-2xl bg-linear-to-br ${app.gradient} flex items-center justify-center transition-transform`}
>
<i className={`pi ${app.icon} text-2xl text-white`} />
</div>
<span className="text-sm font-medium">{app.label}</span>
</Menu.Item>
))}
</Menu.List>
</Menu.Portal>
</Menu>
</div>
);
}
Multiple Menu components can be combined to create a horizontal menubar. By managing the open state and keyboard navigation between menus, a traditional desktop-style menubar can be implemented.
'use client';
import { MenuInstance } from '@primereact/types/shared/menu';
import { Menu } from 'primereact/menu';
import * as React from 'react';
export default function MenubarDemo() {
const menuRefs = React.useRef<Array<MenuInstance | null>>([]);
const [openMenuIndex, setOpenMenuIndex] = React.useState<number | null>(null);
const handleMenuOpenChange = React.useCallback(
(index: number) => (event: { value: boolean }) => {
if (event.value) {
setOpenMenuIndex(index);
} else {
setOpenMenuIndex((prev) => (prev === index ? null : prev));
}
},
[]
);
const handleMenuMouseEnter = React.useCallback(
(index: number) => () => {
if (openMenuIndex !== null) {
setOpenMenuIndex(index);
}
},
[openMenuIndex]
);
const handleMenuKeyDown = React.useCallback(
(index: number) => (event: React.KeyboardEvent) => {
if (event.key === 'ArrowRight') {
event.preventDefault();
const nextIndex = index === menuRefs.current.length - 1 ? 0 : index + 1;
const nextMenu = menuRefs.current[nextIndex];
if (nextMenu?.triggerRef?.current?.elementRef?.current) {
nextMenu.triggerRef.current.elementRef.current.focus();
}
} else if (event.key === 'ArrowLeft') {
event.preventDefault();
const prevIndex = index === 0 ? menuRefs.current.length - 1 : index - 1;
const prevMenu = menuRefs.current[prevIndex];
if (prevMenu?.triggerRef?.current?.elementRef?.current) {
prevMenu.triggerRef.current.elementRef.current.focus();
}
}
},
[]
);
const handleItemClick = React.useCallback(() => {
setOpenMenuIndex(null);
}, []);
return (
<div className="flex justify-center">
<div
className="flex gap-1 bg-surface-100 dark:bg-surface-800 rounded-md p-1 w-fit"
role="menubar"
onMouseLeave={() => setOpenMenuIndex(null)}
>
<Menu
className="w-64"
ref={(el) => {
menuRefs.current[0] = menuRefs.current[0] ?? (el as MenuInstance | null);
}}
open={openMenuIndex === 0}
onOpenChange={handleMenuOpenChange(0)}
>
<Menu.Trigger
variant={openMenuIndex === 0 ? 'filled' : 'text'}
onKeyDown={handleMenuKeyDown(0)}
onMouseEnter={handleMenuMouseEnter(0)}
>
File
</Menu.Trigger>
<Menu.Portal>
<Menu.List>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-file" />
New Document
<span className="ml-auto text-xs opacity-60">⌘ N</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-folder-open" />
Open Project
<span className="ml-auto text-xs opacity-60">⌘ O</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-window-maximize" />
New Window
<span className="ml-auto text-xs opacity-60">⇧ ⌘ N</span>
</Menu.Item>
<Menu.Separator />
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-save" />
Save
<span className="ml-auto text-xs opacity-60">⌘ S</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-download" />
Save As...
<span className="ml-auto text-xs opacity-60">⇧ ⌘ S</span>
</Menu.Item>
</Menu.List>
</Menu.Portal>
</Menu>
<Menu
ref={(el) => {
menuRefs.current[1] = menuRefs.current[1] ?? (el as MenuInstance | null);
}}
open={openMenuIndex === 1}
onOpenChange={handleMenuOpenChange(1)}
>
<Menu.Trigger
variant={openMenuIndex === 1 ? 'filled' : 'text'}
onKeyDown={handleMenuKeyDown(1)}
onMouseEnter={handleMenuMouseEnter(1)}
>
Edit
</Menu.Trigger>
<Menu.Portal>
<Menu.List className="w-64">
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-undo" />
Undo
<span className="ml-auto text-xs opacity-60">⌘ Z</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-replay" />
Redo
<span className="ml-auto text-xs opacity-60">⇧ ⌘ Z</span>
</Menu.Item>
<Menu.Separator />
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-clipboard" />
Cut
<span className="ml-auto text-xs opacity-60">⌘ X</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-copy" />
Copy
<span className="ml-auto text-xs opacity-60">⌘ C</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-file" />
Paste
<span className="ml-auto text-xs opacity-60">⌘ V</span>
</Menu.Item>
</Menu.List>
</Menu.Portal>
</Menu>
<Menu
ref={(el) => {
menuRefs.current[2] = menuRefs.current[2] ?? (el as MenuInstance | null);
}}
open={openMenuIndex === 2}
onOpenChange={handleMenuOpenChange(2)}
>
<Menu.Trigger
variant={openMenuIndex === 2 ? 'filled' : 'text'}
onKeyDown={handleMenuKeyDown(2)}
onMouseEnter={handleMenuMouseEnter(2)}
>
View
</Menu.Trigger>
<Menu.Portal>
<Menu.List className="w-64">
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-search-plus" />
Zoom In
<span className="ml-auto text-xs opacity-60">⌘ +</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-search-minus" />
Zoom Out
<span className="ml-auto text-xs opacity-60">⌘ -</span>
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-refresh" />
Reset Zoom
<span className="ml-auto text-xs opacity-60">⌘ 0</span>
</Menu.Item>
<Menu.Separator />
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-window-maximize" />
Full Screen
<span className="ml-auto text-xs opacity-60">⌃ ⌘ F</span>
</Menu.Item>
</Menu.List>
</Menu.Portal>
</Menu>
<Menu
ref={(el) => {
menuRefs.current[3] = menuRefs.current[3] ?? (el as MenuInstance | null);
}}
open={openMenuIndex === 3}
onOpenChange={handleMenuOpenChange(3)}
>
<Menu.Trigger
variant={openMenuIndex === 3 ? 'filled' : 'text'}
onKeyDown={handleMenuKeyDown(3)}
onMouseEnter={handleMenuMouseEnter(3)}
>
Help
</Menu.Trigger>
<Menu.Portal>
<Menu.List className="w-64">
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-book" />
Documentation
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-github" />
View on GitHub
</Menu.Item>
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-question-circle" />
Support
</Menu.Item>
<Menu.Separator />
<Menu.Item onClick={handleItemClick}>
<i className="pi pi-info-circle" />
About
</Menu.Item>
</Menu.List>
</Menu.Portal>
</Menu>
</div>
</div>
);
}
This demo showcases a typical sidebar layout with two distinct menu sections:
The sidebar uses the Menu component in inline mode (no Portal) for the main navigation.
'use client';
import { Avatar } from 'primereact/avatar';
import { Badge } from 'primereact/badge';
import { Menu } from 'primereact/menu';
import { StyleClass } from 'primereact/styleclass';
import * as React from 'react';
export default function SidebarDemo() {
const menuRef = React.useRef(null);
return (
<div className="flex gap-6">
<div className="w-64 h-240 bg-surface-0 dark:bg-surface-900 border-r border-surface-200 dark:border-surface-700 flex flex-col">
<div className="p-4 border-b border-surface-200 dark:border-surface-700">
<div className="text-xl font-bold text-primary">Prime App</div>
</div>
{/* Top Navigation Menu */}
<div className="flex-1 overflow-y-auto">
<Menu className="border-none">
<Menu.List>
<Menu.Item>
<i className="pi pi-home" />
Dashboard
<Badge shape="circle" className="ml-auto">
8
</Badge>
</Menu.Item>
<Menu.Sub defaultOpen={true}>
<Menu.Trigger>
<i className="pi pi-inbox" />
Inbox
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-envelope" />
All Messages
</Menu.Item>
<Menu.Item>
<i className="pi pi-star" />
Starred
</Menu.Item>
<Menu.Item>
<i className="pi pi-send" />
Sent
</Menu.Item>
<Menu.Item>
<i className="pi pi-trash" />
Trash
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-folder" />
Projects
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-circle-fill text-xs text-blue-500" />
Website Redesign
</Menu.Item>
<Menu.Item>
<i className="pi pi-circle-fill text-xs text-green-500" />
Mobile App
</Menu.Item>
<Menu.Item>
<i className="pi pi-circle-fill text-xs text-orange-500" />
API Integration
</Menu.Item>
<Menu.Separator />
<Menu.Item>
<i className="pi pi-plus" />
New Project
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-users" />
Team
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-users" />
All Members
</Menu.Item>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-sitemap" />
Departments
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-code" />
Engineering
</Menu.Item>
<Menu.Item>
<i className="pi pi-palette" />
Design
</Menu.Item>
<Menu.Item>
<i className="pi pi-chart-line" />
Marketing
</Menu.Item>
<Menu.Item>
<i className="pi pi-dollar" />
Sales
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Item>
<i className="pi pi-user-plus" />
Invite Member
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Separator />
<Menu.Item>
<i className="pi pi-calendar" />
Calendar
</Menu.Item>
<Menu.Sub>
<Menu.Trigger>
<i className="pi pi-chart-bar" />
Analytics
<Menu.Icon />
</Menu.Trigger>
<Menu.List>
<Menu.Item>
<i className="pi pi-eye" />
Overview
</Menu.Item>
<Menu.Item>
<i className="pi pi-chart-line" />
Traffic
</Menu.Item>
<Menu.Item>
<i className="pi pi-users" />
Users
</Menu.Item>
<Menu.Item>
<i className="pi pi-money-bill" />
Revenue
</Menu.Item>
</Menu.List>
</Menu.Sub>
<Menu.Item>
<i className="pi pi-file" />
Documents
</Menu.Item>
<Menu.Separator />
<Menu.Label>
<span className="text-xs font-bold text-surface-500">FAVORITES</span>
</Menu.Label>
<Menu.Item>
<i className="pi pi-star-fill text-yellow-500" />
Important
</Menu.Item>
<Menu.Item>
<i className="pi pi-bookmark-fill text-blue-500" />
Bookmarks
<Badge shape="circle" severity="secondary" className="ml-auto">
5
</Badge>
</Menu.Item>
</Menu.List>
</Menu>
</div>
{/* Bottom User Menu */}
<div className="p-4 border-t border-surface-200 dark:border-surface-700">
<div ref={menuRef} className="hidden overflow-hidden mb-2">
<Menu className="border-none">
<Menu.List className="w-56">
<Menu.Item>
<i className="pi pi-user" />
View Profile
</Menu.Item>
<Menu.Item>
<i className="pi pi-cog" />
Settings
</Menu.Item>
<Menu.Separator />
<Menu.Item>
<i className="pi pi-question-circle" />
Help & Support
</Menu.Item>
<Menu.Separator />
<Menu.Item className="text-red-600 dark:text-red-400">
<i className="pi pi-power-off" />
Sign Out
</Menu.Item>
</Menu.List>
</Menu>
</div>
<StyleClass
as="button"
type="button"
selector="@prev"
enterFromClassName="hidden"
enterActiveClassName="animate-slidedown"
leaveToClassName="hidden"
leaveActiveClassName="animate-fadeout"
className="w-full flex items-center gap-3 p-2 rounded-lg hover:bg-surface-100 dark:hover:bg-surface-800 transition-colors cursor-pointer"
>
<Avatar shape="circle" size="normal">
<Avatar.Image src="https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png" />
<Avatar.Fallback>SA</Avatar.Fallback>
</Avatar>
<div className="flex flex-col items-start flex-1">
<span className="font-semibold text-sm">Sarah Anderson</span>
<span className="text-xs text-surface-500">Online</span>
</div>
<i className="pi pi-ellipsis-v text-sm" />
</StyleClass>
</div>
</div>
<div className="flex-1">
<div className="p-6">
<h2 className="text-2xl font-bold mb-4">Sidebar Menu Demo</h2>
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-900 rounded-lg p-4">
<h3 className="font-bold text-blue-900 dark:text-blue-100 mb-2">Sidebar Layout</h3>
<p className="text-sm text-blue-700 dark:text-blue-300 mb-3">
This demo showcases a typical sidebar layout with two distinct menu sections:
</p>
<ul className="text-sm text-blue-700 dark:text-blue-300 space-y-2 list-disc list-inside">
<li>
<strong>Top Navigation Menu:</strong> Contains main navigation items, organized by category with separators. Features
badge notifications and icon-based navigation.
</li>
<li>
<strong>Bottom User Menu:</strong> A dropdown menu triggered by clicking the user profile area. Provides quick access
to user-related actions and settings.
</li>
</ul>
<p className="text-sm text-blue-700 dark:text-blue-300 mt-3">
The sidebar uses the Menu component in inline mode (no Portal) for the main navigation.
</p>
</div>
</div>
</div>
</div>
);
}
The Menu component supports checkbox and radio items through Menu.CheckboxItem, Menu.RadioGroup and Menu.RadioItem. These items include their respective icons, Menu.CheckboxIcon and Menu.RadioIcon, to visually indicate their state.
'use client';
import { MenuCheckboxItemCheckedChangeEvent, MenuRadioGroupValueChangeEvent } from '@primereact/types/shared/menu';
import { Menu } from 'primereact/menu';
import * as React from 'react';
export default function RadioCheckboxDemo() {
const [notificationsEnabled, setNotificationsEnabled] = React.useState(true);
const [soundEnabled, setSoundEnabled] = React.useState(false);
const [theme, setTheme] = React.useState('light');
return (
<div className="flex justify-center">
<Menu className="w-64">
<Menu.List>
<Menu.Item>Overview</Menu.Item>
<Menu.Separator />
<Menu.Label>Preferences</Menu.Label>
<Menu.CheckboxItem
checked={notificationsEnabled}
onCheckedChange={(e: MenuCheckboxItemCheckedChangeEvent) => setNotificationsEnabled(e.value)}
>
<Menu.CheckboxIcon />
Enable Notifications
</Menu.CheckboxItem>
<Menu.CheckboxItem checked={soundEnabled} onCheckedChange={(e: MenuCheckboxItemCheckedChangeEvent) => setSoundEnabled(e.value)}>
<Menu.CheckboxIcon />
Enable Sound
</Menu.CheckboxItem>
<Menu.Separator />
<Menu.Label>Appearance</Menu.Label>
<Menu.RadioGroup value={theme} onValueChange={(e: MenuRadioGroupValueChangeEvent) => setTheme(e.value as string)}>
<Menu.RadioItem value="light">
<Menu.RadioIcon />
Light Mode
</Menu.RadioItem>
<Menu.RadioItem value="dark">
<Menu.RadioIcon />
Dark Mode
</Menu.RadioItem>
<Menu.RadioItem value="system">
<Menu.RadioIcon />
System Default
</Menu.RadioItem>
</Menu.RadioGroup>
<Menu.Separator />
<Menu.Item>Settings</Menu.Item>
</Menu.List>
</Menu>
</div>
);
}
The Menu component can be integrated with routing libraries. MenuItem supports the as prop to render as Next.js Link components, the onClick prop for programmatic navigation, or standard anchor tags for external links.
'use client';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { Menu } from 'primereact/menu';
export default function RouterDemo() {
const router = useRouter();
const handleProgrammatic = () => {
router.push('/docs/gettingstarted/introduction');
};
return (
<div className="flex justify-center">
<Menu className="w-56">
<Menu.List>
<Menu.Item as={Link} href="/docs/theming/unstyled">
<i className="pi pi-palette" />
Router Link
</Menu.Item>
<Menu.Item onClick={handleProgrammatic}>
<i className="pi pi-link" />
Programmatic
</Menu.Item>
<Menu.Item as="a" href="https://react.dev/" target="_blank">
<i className="pi pi-home" />
External
</Menu.Item>
</Menu.List>
</Menu>
</div>
);
}
Menu component uses the menu role and the value to describe the menu can either be provided with aria-labelledby or aria-label props. Each list item has a menuitem role with aria-label referring to the
label of the item and aria-disabled defined if the item is disabled.
In popup mode, the component implicitly manages the aria-expanded, aria-haspopup and aria-controls attributes of the target element to define the relation between the target and the popup.
| Key | Function |
|---|---|
tab | Add focus to the first item if focus moves in to the menu. If the focus is already within the menu, focus moves to the next focusable item in the page tab sequence. |
shift + tab | Add focus to the first item if focus moves in to the menu. If the focus is already within the menu, focus moves to the previous focusable item in the page tab sequence. |
enter | Activates the focused menuitem. If menu is in overlay mode, popup gets closes and focus moves to target. |
space | Activates the focused menuitem. If menu is in overlay mode, popup gets closes and focus moves to target. |
escape | If menu is in overlay mode, popup gets closes and focus moves to target. |
down arrow | Moves focus to the next menuitem. |
up arrow | Moves focus to the previous menuitem. |
alt + up arrow | If menu is in overlay mode, popup gets closes and focus moves to the target. |
home | Moves focus to the first menuitem. |
end | Moves focus to the last menuitem. |