From e06809e42ea0a134a7da38711907cdad50f222e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:36:26 +0000 Subject: [PATCH 1/2] Extract Autocomplete blur behavior fix and test from #7644 Co-authored-by: iansan5653 <2294248+iansan5653@users.noreply.github.com> --- .../src/Autocomplete/Autocomplete.test.tsx | 24 +++++++++++++++++++ .../src/Autocomplete/AutocompleteInput.tsx | 18 ++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/packages/react/src/Autocomplete/Autocomplete.test.tsx b/packages/react/src/Autocomplete/Autocomplete.test.tsx index 054a9b52e0a..ac92ef3c7ae 100644 --- a/packages/react/src/Autocomplete/Autocomplete.test.tsx +++ b/packages/react/src/Autocomplete/Autocomplete.test.tsx @@ -180,6 +180,30 @@ describe('Autocomplete', () => { await waitFor(() => expect(inputNode.getAttribute('aria-expanded')).not.toBe('true')) }) + it('keeps the menu open when focus moves into the menu', async () => { + const {getByRole} = render( + , + ) + const inputNode = getByRole('combobox') + + expect(inputNode.getAttribute('aria-expanded')).not.toBe('true') + fireEvent.click(inputNode) + fireEvent.keyDown(inputNode, {key: 'ArrowDown'}) + + expect(inputNode.getAttribute('aria-expanded')).toBe('true') + + // Blurring the input while focus moves into the menu should not close the menu, e.g. when + // the user clicks an option in the menu. The blur handler relies on `relatedTarget` to + // detect this rather than the input's ref, so it works regardless of how the ref is wired up. + const menu = getByRole('listbox') + // eslint-disable-next-line github/no-blur + fireEvent.blur(inputNode, {relatedTarget: menu}) + + await waitFor(() => expect(inputNode.getAttribute('aria-expanded')).toBe('true')) + }) + it('sets the input value to the suggested item text and highlights the untyped part of the word', async () => { const user = userEvent.setup() const {container, getByDisplayValue} = render( diff --git a/packages/react/src/Autocomplete/AutocompleteInput.tsx b/packages/react/src/Autocomplete/AutocompleteInput.tsx index f7622d7013a..e60f7af19b2 100644 --- a/packages/react/src/Autocomplete/AutocompleteInput.tsx +++ b/packages/react/src/Autocomplete/AutocompleteInput.tsx @@ -58,11 +58,19 @@ const AutocompleteInput = React.forwardRef( event => { onBlur && onBlur(event) - // HACK: wait a tick and check the focused element before hiding the autocomplete menu - // this prevents the menu from hiding when the user is clicking an option in the Autoselect.Menu, - // but still hides the menu when the user blurs the input by tabbing out or clicking somewhere else on the page + // HACK: wait a tick before hiding the menu so click interactions can complete. + // Use the blur event's relatedTarget to determine whether focus is moving into the + // autocomplete menu; if not, hide the menu when focus leaves the input. Relying on + // relatedTarget instead of `document.activeElement` makes this robust regardless of how + // the input's ref is wired up. safeSetTimeout(() => { - if (document.activeElement !== inputRef.current) { + const nextFocusedElement = event.relatedTarget as Node | null + const menuElement = document.getElementById(`${id}-listbox`) + + if ( + !nextFocusedElement || + (nextFocusedElement !== menuElement && !menuElement?.contains(nextFocusedElement)) + ) { setShowMenu(false) // Reset the input's value to the text the user actually typed rather than leaving the @@ -75,7 +83,7 @@ const AutocompleteInput = React.forwardRef( } }, 0) }, - [onBlur, setShowMenu, inputRef, safeSetTimeout, autocompleteSuggestion, inputValue], + [onBlur, setShowMenu, inputRef, safeSetTimeout, autocompleteSuggestion, inputValue, id], ) const handleInputChange: ChangeEventHandler = event => { From 64f9a95189160768aa5736692bb087a40fbf55ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Jul 2026 14:38:11 +0000 Subject: [PATCH 2/2] Add changeset for Autocomplete blur fix Co-authored-by: iansan5653 <2294248+iansan5653@users.noreply.github.com> --- .changeset/autocomplete-blur-related-target.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/autocomplete-blur-related-target.md diff --git a/.changeset/autocomplete-blur-related-target.md b/.changeset/autocomplete-blur-related-target.md new file mode 100644 index 00000000000..beb635179e4 --- /dev/null +++ b/.changeset/autocomplete-blur-related-target.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +Autocomplete: the input's blur handler now uses the blur event's `relatedTarget` to decide whether to close the menu, so the menu reliably stays open when focus moves into it and closes when focus leaves.