useMenu
Hook that manages menu state, keyboard navigation, focus tracking, and submenu coordination.
Usage#
import { useMenu } from '@primereact/headless/menu';
import { useMenuSubmenu } from '@primereact/headless/menu/submenu';const menu = useMenu();
const sub = useMenuSubmenu({ defaultOpen: true });
const subTriggerProps = menu.getSubTriggerProps({ value: 'projects', sub });useMenu manages focus tracking, keyboard navigation, and submenu orchestration for menu structures. See Primitive for a component-based API.
Features#
- Inline or popup rendering — spread
getListProps()directly for an inline menu, or drive visibility withtriggerPropsandstate.open - Composite submenus —
compositemode enables hover-to-open nested menus with arrow-key navigation across levels - Typed items —
getItemProps({ type })produces menuitem, checkbox, or radio behavior with proper ARIA semantics - Dynamic prop getters —
getItemProps,getSubTriggerProps,getListProps, andgetIndicatorPropsemit props and data attributes per element - Type-ahead search — typing characters moves focus to the matching item label
- Popover integration — built on
usePopoverso positioning, portal, and dismissal are configured through the same options
Working with callbacks#
Controlled popup visibility#
Use open and onOpenChange to drive visibility externally — useful for coordinating with other overlays or toolbar state.
const [open, setOpen] = React.useState(false);
const menu = useMenu({
open,
onOpenChange: (e) => setOpen(e.value)
});
<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>;Submenus with useMenuSubmenu#
Create a separate useMenuSubmenu instance per submenu and wire it through getSubTriggerProps / getListProps.
const menu = useMenu({ composite: true });
const sub = useMenuSubmenu();
const subTriggerProps = menu.getSubTriggerProps({ value: 'files', sub });
const subListProps = menu.getListProps({ value: 'files', sub });Checkbox and radio items#
Pass type and checked to getItemProps and wrap radio items in an element carrying radioGroupProps.
menu.getItemProps({ value: 'notifications', type: 'checkbox', checked: notificationsOn });
menu.getItemProps({ value: 'light', type: 'radio', checked: theme === 'light' });Indicator visibility with match#
getIndicatorProps returns a matchVisible flag so you can render submenu arrows, checkmarks, or radio dots conditionally.
const indicatorProps = menu.getIndicatorProps({ type: 'checkbox', checked: true, match: 'checked' });
{
indicatorProps.matchVisible && <CheckIcon {...indicatorProps} />;
}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", plusdata-value,data-focused,data-disabled,data-checkedgetSubTriggerProps—data-part="subtrigger", plusdata-value,data-focused,data-disabled,data-opengetIndicatorProps—data-part="indicator", plusdata-open/data-closedordata-checked/data-uncheckedgetListProps—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 (navigationmenu). 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. | ||
openDelay | number | 100 |
| The delay in milliseconds before opening the menu when hovering the trigger. Only applies when `openOnHover` is true. | ||
closeDelay | number | 0 |
| The delay in milliseconds before closing the menu when the pointer leaves the trigger. Only applies when `openOnHover` is true. | ||
openOnHover | boolean | false |
| When true, the menu opens on pointer hover over the trigger (in addition to click). | ||
onOpenChange | (event: useMenuOpenChangeEvent) => void | — |
| Callback to invoke when the open state changes. | ||
context | useMenuSubmenuExposes | — |
| Optional parent submenu context whose popover state should drive this menu. When provided, useMenu reuses the parent submenu's popover (anchor, open state, positioner) instead of creating its own. Forwarded by Menu.Root automatically when nested inside a Menu.Submenu. | ||
navigationmenu | useNavigationMenuExposes | — |
| Optional parent NavigationMenu context. When provided, ArrowRight / ArrowLeft pressed on a list item that is not a submenu trigger will move focus to the next / previous sibling navigationmenu trigger (WAI-ARIA NavigationMenu pattern). Forwarded by Menu.Root when nested inside a `NavigationMenu` . | ||
navigationmenuMenuId | string | — |
| The id this menu is registered under in the parent NavigationMenu's trigger registry. Required for `navigationmenu` sibling navigation to know which trigger is "current". | ||
useMenuSubmenu#
| 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. | ||
openDelay | number | 100 |
| The delay in milliseconds before opening the submenu when hovering the subtrigger. Only applies when `openOnHover` is true. | ||
closeDelay | number | 0 |
| The delay in milliseconds before closing the submenu when the pointer leaves the subtrigger. Only applies when `openOnHover` is true. | ||
openOnHover | boolean | true |
| When true, the submenu opens on pointer hover over the subtrigger. | ||
onOpenChange | (event: useMenuSubmenuOpenChangeEvent) => void | — |
| Callback to invoke when the open state changes. | ||
Accessibility#
Arrow keys navigate items, Enter or Space activates the focused item, Escape closes, and type-ahead matches item labels. See Primitive for full WAI-ARIA compliance details.