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 |
|---|---|---|
useMenuSubmenu#
| Name | Type | Default |
|---|---|---|
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.