From f048596efca5398cec4d6387b97390e41e4f9679 Mon Sep 17 00:00:00 2001 From: lkxdsb <17267828919@163.com> Date: Thu, 17 Sep 2026 10:06:35 +0800 Subject: [PATCH 1/2] fix: prevent autoFocus from scrolling dropdown menu --- src/hooks/useAccessibility.ts | 6 +++--- tests/basic.test.tsx | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hooks/useAccessibility.ts b/src/hooks/useAccessibility.ts index 7f31291..a946e39 100644 --- a/src/hooks/useAccessibility.ts +++ b/src/hooks/useAccessibility.ts @@ -27,9 +27,9 @@ export default function useAccessibility({ } }; - const focusMenu = () => { + const focusMenu = (options?: FocusOptions) => { if (overlayRef.current?.focus) { - overlayRef.current.focus(); + overlayRef.current.focus(options); focusMenuRef.current = true; return true; } @@ -62,7 +62,7 @@ export default function useAccessibility({ window.addEventListener('keydown', handleKeyDown); if (autoFocus) { // FIXME: hack with raf - raf(focusMenu, 3); + raf(() => focusMenu({ preventScroll: true }), 3); } return () => { window.removeEventListener('keydown', handleKeyDown); diff --git a/tests/basic.test.tsx b/tests/basic.test.tsx index f6a6e41..b1235d4 100644 --- a/tests/basic.test.tsx +++ b/tests/basic.test.tsx @@ -586,6 +586,7 @@ describe('dropdown', () => { it('should support autoFocus', async () => { jest.useFakeTimers(); + const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus'); const overlay = ( @@ -613,6 +614,7 @@ describe('dropdown', () => { .classList.contains('rc-dropdown-hidden'), ).toBeFalsy(); expect(document.activeElement.className).toContain('menu'); + expect(focusSpy).toHaveBeenCalledWith({ preventScroll: true }); // Close menu with Tab window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab @@ -621,6 +623,7 @@ describe('dropdown', () => { expect(document.activeElement.className).toContain('my-button'); + focusSpy.mockRestore(); jest.useRealTimers(); }); From 862cd287244a47486f8c12b1bc3285ce1ec84846 Mon Sep 17 00:00:00 2001 From: lkxdsb <17267828919@163.com> Date: Thu, 17 Sep 2026 10:19:15 +0800 Subject: [PATCH 2/2] test: always restore autoFocus test state --- tests/basic.test.tsx | 76 +++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/tests/basic.test.tsx b/tests/basic.test.tsx index b1235d4..ed7e5cf 100644 --- a/tests/basic.test.tsx +++ b/tests/basic.test.tsx @@ -588,43 +588,45 @@ describe('dropdown', () => { jest.useFakeTimers(); const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus'); - const overlay = ( - - - one - - two - - ); - const { container } = render( - - - , - ); - const trigger = container.querySelector('.my-button'); - - // Open menu - fireEvent.click(trigger); - - await waitForTime(); - - expect( - container - .querySelector('.rc-dropdown') - .classList.contains('rc-dropdown-hidden'), - ).toBeFalsy(); - expect(document.activeElement.className).toContain('menu'); - expect(focusSpy).toHaveBeenCalledWith({ preventScroll: true }); - - // Close menu with Tab - window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab - - await waitForTime(); - - expect(document.activeElement.className).toContain('my-button'); - - focusSpy.mockRestore(); - jest.useRealTimers(); + try { + const overlay = ( + + + one + + two + + ); + const { container } = render( + + + , + ); + const trigger = container.querySelector('.my-button'); + + // Open menu + fireEvent.click(trigger); + + await waitForTime(); + + expect( + container + .querySelector('.rc-dropdown') + .classList.contains('rc-dropdown-hidden'), + ).toBeFalsy(); + expect(document.activeElement.className).toContain('menu'); + expect(focusSpy).toHaveBeenCalledWith({ preventScroll: true }); + + // Close menu with Tab + window.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 9 })); // Tab + + await waitForTime(); + + expect(document.activeElement.className).toContain('my-button'); + } finally { + focusSpy.mockRestore(); + jest.useRealTimers(); + } }); it('children cannot be given ref should not throw', () => {