useMenu
Hook that manages menu state, keyboard navigation, focus tracking, and submenu coordination.
- Dashboard
- Workspace
- Analytics
- Projects
- Active Projects
- Recent
- Favorites
- Completed
- Help & Support
Usage#
import { useMenu } from '@primereact/headless/menu';
import { useMenuSub } from '@primereact/headless/menu/sub';
const menu = useMenu();
const sub = useMenuSub({ defaultOpen: true });
const subTriggerProps = menu.getSubTriggerProps({ value: 'projects', sub });
return (
<div {...menu.rootProps}>
<ul {...menu.getListProps()}>
<li {...menu.getItemProps({ value: 'item1' })}></li>
<li {...sub.subProps}>
<div {...subTriggerProps}></div>
<ul {...menu.getListProps({ value: 'projects', sub })}></ul>
</li>
</ul>
</div>
);useMenu manages focus tracking, keyboard navigation, and submenu orchestration for menu structures — see Primitive for a component-based API.
Features#
- Returns spread-ready prop objects:
rootProps,triggerProps,labelProps,separatorProps,radioGroupProps - Dynamic prop getters:
getItemProps,getSubTriggerProps,getListProps,getIndicatorProps - Built-in character search to jump to items by typing
- Composite mode for nested menus with hover-to-open submenu behavior
- Portal-based popup rendering with configurable positioning via
usePopover - Checkbox and radio item types with
getItemProps({ type: 'checkbox' | 'radio' })
Behavior#
Inline Menu#
By default, useMenu renders an inline menu. Spread rootProps on the container and getListProps() on the list element.
const menu = useMenu();Portal (Popup) Menu#
When the popover is used, spread triggerProps on a button to toggle visibility. Use state.open to conditionally render the popup.
const menu = useMenu();
<button {...menu.triggerProps}>Open</button>;
{
menu.state.open && <ul {...menu.getListProps()}>...</ul>;
}Composite Mode#
Set composite to enable nested submenu behavior with hover-to-open and arrow key navigation across submenu levels.
const menu = useMenu({ composite: true });Submenus#
Use useMenuSub for each submenu. Pass the sub instance to getSubTriggerProps and getListProps to wire up open/close behavior.
const sub = useMenuSub();
const subTriggerProps = menu.getSubTriggerProps({ value: 'files', sub });
const subListProps = menu.getListProps({ value: 'files', sub });Checkbox and Radio Items#
Pass type and checked to getItemProps for checkbox or radio behavior. Wrap radio items in an element with radioGroupProps.
menu.getItemProps({ value: 'notifications', type: 'checkbox', checked: true });
menu.getItemProps({ value: 'light', type: 'radio', checked: selectedTheme === 'light' });Indicator Props#
getIndicatorProps returns visibility state and data attributes for submenu arrows, checkmarks, or radio dots. Use match to control when the indicator is visible.
const indicatorProps = menu.getIndicatorProps({ type: 'checkbox', checked: true, match: 'checked' });
// indicatorProps.matchVisible === trueControlled Visibility#
Use open and onOpenChange for programmatic control over the popup state.
const [open, setOpen] = React.useState(false);
const menu = useMenu({ open, onOpenChange: (e) => setOpen(e.value) });Custom Styling with Data Attributes#
All prop getters attach data-scope="menu" and a data-part attribute for CSS targeting. Additional data attributes reflect runtime state:
getItemProps — data-part="item", plus data-value, data-focused (keyboard/mouse focus), data-disabled, and data-checked (for checkbox/radio items).
getSubTriggerProps — data-part="subtrigger", plus data-value, data-focused, data-disabled, and data-open (when its submenu is expanded).
getIndicatorProps — data-part="indicator", plus data-open/data-closed (submenu indicators) or data-checked/data-unchecked (checkbox/radio indicators).
getListProps — data-part="list".
[data-scope='menu'][data-part='item'][data-focused] {
background-color: var(--surface-hover);
}
[data-scope='menu'][data-part='item'][data-checked] {
font-weight: 600;
}
[data-scope='menu'][data-part='subtrigger'][data-open] {
background-color: var(--surface-hover);
}
[data-scope='menu'][data-part='indicator'][data-checked] {
color: var(--primary);
}
[data-scope='menu'][data-part='item'][data-disabled] {
opacity: 0.6;
pointer-events: none;
}API#
useMenu#
| Name | Type | Default |
|---|---|---|
open | boolean | — |
| Controlled open state of the menu. | ||
defaultOpen | boolean | false |
| Default open state for uncontrolled mode. | ||
composite | boolean | false |
| Whether the menu is in composite mode (menubar). In composite mode, submenus open on hover and focusedOptionId is an array tracking the focus path. | ||
appendTo | "body" | HTMLElement | "self" | 'body' |
| The element to which the overlay is appended. | ||
baseZIndex | number | 0 |
| Base zIndex value to use in layering. | ||
autoZIndex | boolean | true |
| Whether to automatically manage layering. | ||
tabIndex | number | 0 |
| Index of the element in tabbing order. | ||
onOpenChange | (event: useMenuOpenChangeEvent) => void | — |
| Callback to invoke when the open state changes. | ||
useMenuSub#
| Name | Type | Default |
|---|---|---|
open | boolean | — |
| Controlled open state of the submenu. | ||
defaultOpen | boolean | false |
| Default open state for uncontrolled mode. | ||
disabled | boolean | false |
| Whether the submenu is disabled. | ||
onOpenChange | (event: useMenuSubOpenChangeEvent) => void | — |
| Callback to invoke when the open state changes. | ||
Accessibility#
See Menu Primitive for WAI-ARIA compliance details and keyboard support.