Provide a general summary of the issue here
Collection components rendered alongside TabList inside Tabs throw, because they render during the Tabs collection's hidden pass and contribute items to the Tabs document instead of building their own.
#10019 addressed this by making MenuTrigger, Select and ComboBox hideable, and #10367 adds DialogTrigger. Two shapes remain that a per-trigger guard doesn't reach — and the second can't be reached by that strategy at all, because there is no trigger component to guard.
🤔 Expected Behavior?
Collection components in the tab row build their own collection and render normally.
😯 Current Behavior
1. A TagGroup in the tab row (e.g. chips for currently-applied filters, beside the tabs):
TypeError: Cannot destructure property 'onAction' of '_utils.listMap.get(...)' as it is undefined.
2. A standalone controlled Popover (triggerRef + isOpen, no trigger component) containing a Menu:
TypeError: Cannot read properties of null (reading 'isDisabled') // useMenuItem.ts:173
The second is the interesting one: the hideable-trigger approach can't cover it, since the popover is positioned via triggerRef rather than wrapped in a MenuTrigger/DialogTrigger.
Reduced further, a bare Menu, ListBox or GridList as a sibling of TabList throws for the same reason (three different internal errors). Those are minimal reductions rather than realistic usage — the two above are the ones I would actually expect people to write.
💁 Possible Solution
No PR, since this is a design call rather than a patch.
The per-trigger guards stop the gateway rendering. The underlying rule — a collection component should not contribute items to an unrelated ancestor's collection document — isn't enforced anywhere, so each new shape needs its own guard, and shapes without a trigger have nowhere to put one.
CollectionBuilder is where the rule could live:
// If a document was provided above us, we're already in a hidden tree. Just render the content.
let doc = useContext(CollectionDocumentContext);
if (doc) {
return props.content as ReactElement;
}
Correct for a nested collection that genuinely belongs to the ancestor (submenu items joining the parent menu, Select's ListBox); wrong for an independent collection root that merely happens to be nested. Distinguishing those — perhaps opt-in from the components that need inheritance — would cover all of these at once.
🔦 Context
Found while fixing DialogTrigger (#10367) for a tab row containing a filter popover. That PR fixes our case; this issue is only about the shapes it doesn't reach.
💻 Code Sample
function inTabs(node) {
return (
<Tabs>
<div>
<TabList>
<Tab id="key1">First Tab</Tab>
<Tab id="key2">Second Tab</Tab>
</TabList>
{node}
</div>
<TabPanel id="key1">A</TabPanel>
<TabPanel id="key2">B</TabPanel>
</Tabs>
);
}
// 1. TagGroup in the tab row
render(inTabs(
<TagGroup aria-label="Active filters">
<TagList><Tag id="a">Filter A</Tag></TagList>
</TagGroup>
));
// 2. standalone controlled Popover holding a Menu
function StandalonePopover() {
let ref = useRef(null);
return (
<>
<Button ref={ref}>Open</Button>
<Popover triggerRef={ref} isOpen={false} aria-label="Filters">
<Menu aria-label="Filter options"><MenuItem>Item 1</MenuItem></Menu>
</Popover>
</>
);
}
render(inTabs(<StandalonePopover />));
Control: the identical Menu element renders fine with no Tabs wrapper, and nested inside plain divs — the Tabs wrapper is the only variable.
🌍 Your Environment
| Software |
Version(s) |
| react-aria-components |
1.19.0 / main (with #10367 applied) |
| Browser |
n/a (reproduces in jsdom) |
| Operating System |
macOS |
Provide a general summary of the issue here
Collection components rendered alongside
TabListinsideTabsthrow, because they render during theTabscollection's hidden pass and contribute items to theTabsdocument instead of building their own.#10019 addressed this by making
MenuTrigger,SelectandComboBoxhideable, and #10367 addsDialogTrigger. Two shapes remain that a per-trigger guard doesn't reach — and the second can't be reached by that strategy at all, because there is no trigger component to guard.🤔 Expected Behavior?
Collection components in the tab row build their own collection and render normally.
😯 Current Behavior
1. A
TagGroupin the tab row (e.g. chips for currently-applied filters, beside the tabs):2. A standalone controlled
Popover(triggerRef+isOpen, no trigger component) containing aMenu:The second is the interesting one: the hideable-trigger approach can't cover it, since the popover is positioned via
triggerRefrather than wrapped in aMenuTrigger/DialogTrigger.Reduced further, a bare
Menu,ListBoxorGridListas a sibling ofTabListthrows for the same reason (three different internal errors). Those are minimal reductions rather than realistic usage — the two above are the ones I would actually expect people to write.💁 Possible Solution
No PR, since this is a design call rather than a patch.
The per-trigger guards stop the gateway rendering. The underlying rule — a collection component should not contribute items to an unrelated ancestor's collection document — isn't enforced anywhere, so each new shape needs its own guard, and shapes without a trigger have nowhere to put one.
CollectionBuilderis where the rule could live:Correct for a nested collection that genuinely belongs to the ancestor (submenu items joining the parent menu,
Select'sListBox); wrong for an independent collection root that merely happens to be nested. Distinguishing those — perhaps opt-in from the components that need inheritance — would cover all of these at once.🔦 Context
Found while fixing
DialogTrigger(#10367) for a tab row containing a filter popover. That PR fixes our case; this issue is only about the shapes it doesn't reach.💻 Code Sample
Control: the identical
Menuelement renders fine with noTabswrapper, and nested inside plaindivs — theTabswrapper is the only variable.🌍 Your Environment
main(with #10367 applied)