Provide a general summary of the feature here
trigger="contextMenu" (new in v1.20.0) works well for a standalone trigger, but there doesn't appear to be a supported way to use it on a collection item — a GridListItem, TreeItem, or table Row. Right-clicking a row to open the same menu its kebab button opens seems like one of the most common reasons to want a context menu, so I suspect this is either a gap or a pattern I've failed to find.
Either a supported API for it, or docs guidance on the intended approach, would help.
🤔 Expected Behavior?
Being able to attach a context menu to a collection item, so that right-click / long-press / Shift+F10 on a row opens the same menu the row's kebab button opens.
Collection items already look like valid trigger candidates: the docs say MenuTrigger "works with any pressable React Aria component", and rows are pressable —
useGridListItem → useSelectableItem → usePress (useSelectableItem.ts:409)
usePress reads PressResponderContext (usePress.ts:112) and merges the remaining DOM props into its result (usePress.ts:1010)
so a row would consume MenuTrigger's onContextMenu / onKeyDown correctly if it could receive them.
😯 Current Behavior
1. MenuTrigger can't wrap a collection item. MenuTrigger must render as an ancestor of its trigger, but inside a collection it hits the useIsHidden guard and returns null during the collection-building pass, so the item never registers. Wrapping a TreeItem removes every row from the tree — the collection renders empty.
2. Wrapping the row's content in <Pressable> works, but warns once per row. The Pressable child ends up being a div with no interactive ARIA role. The row itself is role="row" (RAC's Tree is a treegrid), which isn't in Pressable's allowed-role list, so there's nothing valid to put the role on:
<Pressable> child must have an interactive ARIA role.
Adding excludeFromTabOrder just swaps it for the other warning:
<Pressable> child must be focusable. Please ensure the tabIndex prop is passed through.
Putting a fake interactive role on a div inside a treegrid row seems worse than the warning, so neither option feels right.
3. Every example uses a standalone <Button>. packages/react-aria-components/stories/Menu.stories.tsx:532, packages/@react-spectrum/s2/stories/Menu.stories.tsx:409, and packages/react-aria-components/test/Menu.test.tsx:652 / :701, plus both docs sites. As a side note, the docs example makes a non-interactive 250×150 region into a <button> purely to satisfy the pressable requirement — it's announced as a button but does nothing when pressed, which reads a little odd as the canonical example.
💁 Possible Solution
useContextMenu works today and looks like the intended escape hatch — contextMenuProps spread straight onto a TreeItem / GridListItem keeps all the platform handling, with no wrapper and no warnings. If that's the recommended pattern for collections, documenting it on the Menu page (or on GridList / Tree / Table) would settle it.
The one thing it loses versus MenuTrigger is positioning the menu at the pointer, which needs getTargetRect — that isn't part of Popover's public types, so it currently needs a @ts-expect-error. Exposing it, or otherwise providing a supported way to anchor a popover to a point, would close that gap.
🔦 Context
We have a collections sidebar built on Tree, where each row has a kebab menu (rename, share, delete, …). We wanted right-click on the row to open that same menu, keeping the kebab button as-is. The kebab stays either way — the context menu is an addition, not a replacement.
We landed on <Pressable> around the row content, which works, but it restructures the row purely to host the trigger and logs a warning per row in development, so it doesn't feel like the intended shape.
💻 Examples
Wrapping the item — collection renders empty:
// Every row disappears: MenuTrigger returns null during the collection build,
// so no TreeItem is ever registered.
<Tree aria-label="Collections">
<MenuTrigger trigger="contextMenu">
<TreeItem textValue="Design">
<TreeItemContent>Design</TreeItemContent>
</TreeItem>
<Popover>
<Menu>
<MenuItem>Rename…</MenuItem>
<MenuItem>Delete…</MenuItem>
</Menu>
</Popover>
</MenuTrigger>
</Tree>
Wrapping the content — works, but warns once per row:
<TreeItem textValue="Design">
<TreeItemContent>
<MenuTrigger trigger="contextMenu">
{/* warns: child must have an interactive ARIA role */}
<Pressable><div className="row-content">Design</div></Pressable>
<Popover>
<Menu>
<MenuItem>Rename…</MenuItem>
<MenuItem>Delete…</MenuItem>
</Menu>
</Popover>
</MenuTrigger>
</TreeItemContent>
</TreeItem>
Possibly related: #7197 (pass onContextMenu in RAC Tab), #7987 (useLongPress with a Table Row — event and labelling props get filtered out), #9863 (right-click a table row containing a link).
Versions: react-aria-components@1.20.0, react-aria@3.51.0, react-stately@3.49.0, React 19.
🧢 Your Company/Team
Metaview
Provide a general summary of the feature here
trigger="contextMenu"(new in v1.20.0) works well for a standalone trigger, but there doesn't appear to be a supported way to use it on a collection item — aGridListItem,TreeItem, or tableRow. Right-clicking a row to open the same menu its kebab button opens seems like one of the most common reasons to want a context menu, so I suspect this is either a gap or a pattern I've failed to find.Either a supported API for it, or docs guidance on the intended approach, would help.
🤔 Expected Behavior?
Being able to attach a context menu to a collection item, so that right-click / long-press / Shift+F10 on a row opens the same menu the row's kebab button opens.
Collection items already look like valid trigger candidates: the docs say
MenuTrigger"works with any pressable React Aria component", and rows are pressable —useGridListItem→useSelectableItem→usePress(useSelectableItem.ts:409)usePressreadsPressResponderContext(usePress.ts:112) and merges the remaining DOM props into its result (usePress.ts:1010)so a row would consume
MenuTrigger'sonContextMenu/onKeyDowncorrectly if it could receive them.😯 Current Behavior
1.
MenuTriggercan't wrap a collection item.MenuTriggermust render as an ancestor of its trigger, but inside a collection it hits theuseIsHiddenguard and returnsnullduring the collection-building pass, so the item never registers. Wrapping aTreeItemremoves every row from the tree — the collection renders empty.2. Wrapping the row's content in
<Pressable>works, but warns once per row. ThePressablechild ends up being adivwith no interactive ARIA role. The row itself isrole="row"(RAC's Tree is a treegrid), which isn't inPressable's allowed-role list, so there's nothing valid to put the role on:Adding
excludeFromTabOrderjust swaps it for the other warning:Putting a fake interactive role on a
divinside atreegridrow seems worse than the warning, so neither option feels right.3. Every example uses a standalone
<Button>.packages/react-aria-components/stories/Menu.stories.tsx:532,packages/@react-spectrum/s2/stories/Menu.stories.tsx:409, andpackages/react-aria-components/test/Menu.test.tsx:652/:701, plus both docs sites. As a side note, the docs example makes a non-interactive 250×150 region into a<button>purely to satisfy the pressable requirement — it's announced as a button but does nothing when pressed, which reads a little odd as the canonical example.💁 Possible Solution
useContextMenuworks today and looks like the intended escape hatch —contextMenuPropsspread straight onto aTreeItem/GridListItemkeeps all the platform handling, with no wrapper and no warnings. If that's the recommended pattern for collections, documenting it on the Menu page (or on GridList / Tree / Table) would settle it.The one thing it loses versus
MenuTriggeris positioning the menu at the pointer, which needsgetTargetRect— that isn't part ofPopover's public types, so it currently needs a@ts-expect-error. Exposing it, or otherwise providing a supported way to anchor a popover to a point, would close that gap.🔦 Context
We have a collections sidebar built on
Tree, where each row has a kebab menu (rename, share, delete, …). We wanted right-click on the row to open that same menu, keeping the kebab button as-is. The kebab stays either way — the context menu is an addition, not a replacement.We landed on
<Pressable>around the row content, which works, but it restructures the row purely to host the trigger and logs a warning per row in development, so it doesn't feel like the intended shape.💻 Examples
Wrapping the item — collection renders empty:
Wrapping the content — works, but warns once per row:
Possibly related: #7197 (pass
onContextMenuin RACTab), #7987 (useLongPresswith a Table Row — event and labelling props get filtered out), #9863 (right-click a table row containing a link).Versions:
react-aria-components@1.20.0,react-aria@3.51.0,react-stately@3.49.0, React 19.🧢 Your Company/Team
Metaview