Skip to content

Commit 95f8c41

Browse files
aman44444ZeeshanTamboli
authored andcommitted
[autocomplete] Fix popup reopening on window focus regain with openOnFocus (#47790)
Co-authored-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com>
1 parent d13a72d commit 95f8c41

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

packages/mui-material/src/Autocomplete/Autocomplete.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,36 @@ describe('<Autocomplete />', () => {
15731573
fireEvent.click(textbox);
15741574
expect(textbox).to.have.attribute('aria-expanded', 'false');
15751575
});
1576+
1577+
it('does not reopen when window focus is regained', () => {
1578+
render(
1579+
<Autocomplete
1580+
options={['one', 'two', 'three']}
1581+
openOnFocus
1582+
renderInput={(params) => <TextField {...params} autoFocus />}
1583+
/>,
1584+
);
1585+
const textbox = screen.getByRole('combobox');
1586+
1587+
expect(textbox).to.have.attribute('aria-expanded', 'true');
1588+
1589+
act(() => {
1590+
document.activeElement.blur();
1591+
});
1592+
fireEvent.blur(window);
1593+
1594+
expect(textbox).to.have.attribute('aria-expanded', 'false');
1595+
1596+
fireEvent.focus(textbox);
1597+
expect(textbox).to.have.attribute('aria-expanded', 'false');
1598+
1599+
act(() => {
1600+
document.activeElement.blur();
1601+
});
1602+
1603+
fireEvent.focus(textbox);
1604+
expect(textbox).to.have.attribute('aria-expanded', 'true');
1605+
});
15761606
});
15771607

15781608
describe('listbox wrapping behavior', () => {

packages/mui-material/src/useAutocomplete/useAutocomplete.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ function useAutocomplete(props) {
147147
const firstFocus = React.useRef(true);
148148
const inputRef = React.useRef(null);
149149
const listboxRef = React.useRef(null);
150+
const windowLostFocus = React.useRef(false);
150151
const [anchorEl, setAnchorEl] = React.useState(null);
151152

152153
const [focusedItem, setFocusedItem] = React.useState(-1);
@@ -619,6 +620,24 @@ function useAutocomplete(props) {
619620
}
620621
}, [syncHighlightedIndex, filteredOptionsChanged, popupOpen, disableCloseOnSelect]);
621622

623+
// Listen for browser window blur to detect when the user switches tabs or windows.
624+
// This helps prevent the popup from reopening automatically when the window regains focus.
625+
React.useEffect(() => {
626+
if (typeof window === 'undefined') {
627+
return undefined;
628+
}
629+
630+
const handleWindowBlur = () => {
631+
windowLostFocus.current = true;
632+
};
633+
634+
window.addEventListener('blur', handleWindowBlur);
635+
636+
return () => {
637+
window.removeEventListener('blur', handleWindowBlur);
638+
};
639+
}, []);
640+
622641
const handleOpen = (event) => {
623642
if (open) {
624643
return;
@@ -995,6 +1014,14 @@ function useAutocomplete(props) {
9951014
focusItem(-1);
9961015
}
9971016

1017+
// If the window previously lost focus while the popup was open,
1018+
// ignore this focus event to prevent unintended reopening.
1019+
// Reset the flag so normal focus behavior resumes.
1020+
if (windowLostFocus.current) {
1021+
windowLostFocus.current = false;
1022+
return;
1023+
}
1024+
9981025
if (openOnFocus && !ignoreFocus.current) {
9991026
handleOpen(event);
10001027
}

0 commit comments

Comments
 (0)