fix: Keep Portaled Dropdown Menus Clickable Inside Modal Dialogs (#15026)

* fix: keep portaled dropdown menus clickable inside modal dialogs

Modal OGDialog layers set pointer-events: none on body and re-enable it
only on their own content. A portaled DropdownPopup menu is a body-level
sibling of those layers, so it inherited pointer-events: none: hover
never reached the items and every click passed through to nothing, which
Ariakit treated as an outside interaction and closed the menu.

This made the Agent File Search and File Context upload menus dead when
SharePoint was enabled, since that flag is what switches them from a
plain in-dialog button to the portaled menu.

Restore pointer-events: auto on the menu element so it stays clickable
regardless of the surrounding modal layers.

Fixes #14487

* fix: sort imports in DropdownPopup spec
This commit is contained in:
Marco Beretta 2026-08-20 17:20:42 +02:00 committed by GitHub
parent f1fbaeb6d8
commit bf3fb17b58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 40 additions and 1 deletions

View file

@ -0,0 +1,35 @@
import React from 'react';
import * as Ariakit from '@ariakit/react';
import { render } from '@testing-library/react';
import DropdownPopup from './DropdownPopup';
describe('DropdownPopup', () => {
it('restores pointer events on portaled menus so they stay clickable inside modal dialogs', () => {
// A modal Radix dialog (OGDialog) sets `pointer-events: none` on body and only
// re-enables it on its own content. A portaled menu is a body-level sibling and
// would inherit `none`, making every item hit-transparent (#14487).
document.body.style.pointerEvents = 'none';
render(
<DropdownPopup
menuId="portal-click-test-menu"
isOpen={true}
setIsOpen={jest.fn()}
modal={true}
unmountOnHide={true}
trigger={
<Ariakit.MenuButton>
<span>trigger</span>
</Ariakit.MenuButton>
}
items={[{ label: 'From Local Computer', onClick: jest.fn() }]}
/>,
);
const menu = document.getElementById('portal-click-test-menu');
expect(menu).not.toBeNull();
expect(menu?.style.pointerEvents).toBe('auto');
document.body.style.pointerEvents = '';
});
});

View file

@ -89,7 +89,11 @@ const Menu: React.FC<MenuProps> = ({
finalFocus={finalFocus}
unmountOnHide={unmountOnHide}
preserveTabOrder={preserveTabOrder}
style={{ zIndex, ...style }}
/* Portaled menus land beside modal OGDialog layers, which set
`pointer-events: none` on body and re-enable it only on their own
content. Without this the menu inherits `none` and its items become
hit-transparent (danny-avila/LibreChat#14487). */
style={{ zIndex, pointerEvents: 'auto', ...style }}
className={cn('popover-ui', className)}
{...props}
>