From 961baf924f9687f70260cb1c6a0255dbbb9eb65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E5=BB=B7=E5=AE=89?= <73953029+nrps9909@users.noreply.github.com> Date: Wed, 2 Sep 2026 13:59:35 +0800 Subject: [PATCH 1/3] fix: focus wrapped dropdown menus --- src/hooks/useAccessibility.ts | 20 +++++++++++++++----- tests/basic.test.tsx | 9 ++++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/hooks/useAccessibility.ts b/src/hooks/useAccessibility.ts index a946e39..84b562c 100644 --- a/src/hooks/useAccessibility.ts +++ b/src/hooks/useAccessibility.ts @@ -28,12 +28,22 @@ export default function useAccessibility({ }; const focusMenu = (options?: FocusOptions) => { - if (overlayRef.current?.focus) { - overlayRef.current.focus(options); - focusMenuRef.current = true; - return true; + const overlay = overlayRef.current; + if (!overlay?.focus) { + return false; } - return false; + + const activeElement = document.activeElement; + overlay.focus(options); + if (document.activeElement === activeElement) { + const focusTarget = (overlay.querySelector?.('[role="menu"]') ?? + overlay.querySelector?.('[tabindex]')) as HTMLElement | null; + focusTarget?.focus(options); + } + + const focused = document.activeElement !== activeElement; + focusMenuRef.current = focused; + return focused; }; const handleKeyDown = (event) => { diff --git a/tests/basic.test.tsx b/tests/basic.test.tsx index ed7e5cf..937533f 100644 --- a/tests/basic.test.tsx +++ b/tests/basic.test.tsx @@ -492,9 +492,16 @@ describe('dropdown', () => { // Focus menu with Tab window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab + expect(document.activeElement).toHaveClass('rc-menu'); + fireEvent.keyDown(document.activeElement, { + key: 'ArrowDown', + keyCode: 40, + }); + await sleep(50); + expect(document.activeElement).toHaveTextContent('one'); // Close menu with Tab - window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab + fireEvent.keyDown(document.activeElement, { key: 'Tab', keyCode: 9 }); await sleep(200); expect(document.activeElement.className).toContain('my-button'); }); From a3263300d3ac45f7eaffcf16eaf3c5e4e9c2073d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E5=BB=B7=E5=AE=89?= <73953029+nrps9909@users.noreply.github.com> Date: Wed, 2 Sep 2026 15:36:29 +0800 Subject: [PATCH 2/3] fix: preserve optional overlay refs --- src/hooks/useAccessibility.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useAccessibility.ts b/src/hooks/useAccessibility.ts index 84b562c..0f6d26f 100644 --- a/src/hooks/useAccessibility.ts +++ b/src/hooks/useAccessibility.ts @@ -28,7 +28,7 @@ export default function useAccessibility({ }; const focusMenu = (options?: FocusOptions) => { - const overlay = overlayRef.current; + const overlay = overlayRef?.current; if (!overlay?.focus) { return false; } From e6c87ed9e7bdedc9eb27a098a203c7cf278b752f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E5=BB=B7=E5=AE=89?= <73953029+nrps9909@users.noreply.github.com> Date: Thu, 17 Sep 2026 16:19:39 +0800 Subject: [PATCH 3/3] test: preserve wrapped menu autoFocus scroll options --- tests/basic.test.tsx | 93 ++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/tests/basic.test.tsx b/tests/basic.test.tsx index 937533f..a5987d0 100644 --- a/tests/basic.test.tsx +++ b/tests/basic.test.tsx @@ -591,50 +591,57 @@ describe('dropdown', () => { jest.useRealTimers(); }); - it('should support autoFocus', async () => { - jest.useFakeTimers(); - const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus'); + it.each(['direct', 'wrapped'])( + 'should support autoFocus for a %s menu', + async (mode) => { + jest.useFakeTimers(); + const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus'); + + try { + const overlay = ( +
+ ); + const { container } = render( +