Skip to content

Commit ee3ce73

Browse files
committed
fix: prevent focus recursion in DropdownMenuContent
Adds event propagation stop to DropdownMenuContent to prevent infinite focus loops when used inside Dialogs. Mirrors the fix applied to SelectContent in 889da63.
1 parent ff62aab commit ee3ce73

File tree

1 file changed

+15
-14
lines changed

1 file changed

+15
-14
lines changed

src/components/ui/dropdown-menu.tsx

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,43 +66,43 @@ const DropdownMenuContent = React.forwardRef<
6666
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
6767
>(
6868
(
69-
{ className, sideOffset = 4, onPointerDown, onPointerDownOutside, onCloseAutoFocus, ...props },
69+
{ className, sideOffset = 4, onPointerDown, onPointerDownOutside, onCloseAutoFocus, onFocus, ...props },
7070
ref,
7171
) => {
72-
const isCloseFromMouse = React.useRef<boolean>(false);
73-
7472
const handlePointerDown = React.useCallback(
7573
(e: PointerDownEvent) => {
76-
isCloseFromMouse.current = true;
7774
onPointerDown?.(e);
7875
},
7976
[onPointerDown],
8077
);
8178

8279
const handlePointerDownOutside = React.useCallback(
8380
(e: PointerDownOutsideEvent) => {
84-
isCloseFromMouse.current = true;
8581
onPointerDownOutside?.(e);
8682
},
8783
[onPointerDownOutside],
8884
);
8985

9086
const handleCloseAutoFocus = React.useCallback(
9187
(e: Event) => {
92-
if (onCloseAutoFocus) {
93-
return onCloseAutoFocus(e);
94-
}
95-
96-
if (!isCloseFromMouse.current) {
97-
return;
98-
}
99-
88+
// Prevent default focus restoration to avoid conflicts with parent focus scopes (Sheet/Dialog)
89+
// This is critical to prevent "too much recursion" errors
10090
e.preventDefault();
101-
isCloseFromMouse.current = false;
91+
e.stopPropagation();
92+
onCloseAutoFocus?.(e);
10293
},
10394
[onCloseAutoFocus],
10495
);
10596

97+
const handleFocus = React.useCallback(
98+
(e: React.FocusEvent<HTMLDivElement>) => {
99+
// Stop propagation to prevent focus events from reaching parent focus scopes
100+
e.stopPropagation();
101+
onFocus?.(e);
102+
},
103+
[onFocus],
104+
);
105+
106106
return (
107107
<DropdownMenuPrimitive.Portal>
108108
<DropdownMenuPrimitive.Content
@@ -115,6 +115,7 @@ const DropdownMenuContent = React.forwardRef<
115115
onPointerDown={handlePointerDown}
116116
onPointerDownOutside={handlePointerDownOutside}
117117
onCloseAutoFocus={handleCloseAutoFocus}
118+
onFocus={handleFocus}
118119
{...props}
119120
/>
120121
</DropdownMenuPrimitive.Portal>

0 commit comments

Comments
 (0)