diff --git a/packages/react-aria/src/interactions/utils.ts b/packages/react-aria/src/interactions/utils.ts
index 21878b6833a..429afde9cb4 100644
--- a/packages/react-aria/src/interactions/utils.ts
+++ b/packages/react-aria/src/interactions/utils.ts
@@ -13,7 +13,7 @@
import {FocusableElement} from '@react-types/shared';
import {focusWithoutScrolling} from '../utils/focusWithoutScrolling';
import {getActiveElement, getEventTarget, nodeContains} from '../utils/shadowdom/DOMFunctions';
-import {getOwnerWindow, isShadowRoot} from '../utils/domHelpers';
+import {getOwnerWindow, isNode, isShadowRoot} from '../utils/domHelpers';
import {isFocusable} from '../utils/isFocusable';
import {FocusEvent as ReactFocusEvent, SyntheticEvent, useCallback, useRef} from 'react';
import {useLayoutEffect} from '../utils/useLayoutEffect';
@@ -138,12 +138,12 @@ export function preventFocus(target: FocusableElement | null): (() => void) | un
// Focus is "moving to target" when it moves to the button or to a descendant of the button
// (e.g. SVG icon)
let isFocusMovingToTarget = (focusTarget: Element | null) =>
- focusTarget === target || (focusTarget != null && nodeContains(target, focusTarget));
+ focusTarget === target || (isNode(focusTarget) && nodeContains(target, focusTarget));
// Blur/focusout events have their target as the element losing focus. Stop propagation when
// that is the previously focused element (activeElement) or a descendant (e.g. in shadow DOM).
let isBlurFromActiveElement = (eventTarget: Element | null) =>
eventTarget === activeElement ||
- (activeElement != null && eventTarget != null && nodeContains(activeElement, eventTarget));
+ (activeElement != null && isNode(eventTarget) && nodeContains(activeElement, eventTarget));
ignoreFocusEvent = true;
let isRefocusing = false;
diff --git a/packages/react-aria/test/interactions/usePress.test.js b/packages/react-aria/test/interactions/usePress.test.js
index ec848c7467f..1f944d2d9ca 100644
--- a/packages/react-aria/test/interactions/usePress.test.js
+++ b/packages/react-aria/test/interactions/usePress.test.js
@@ -1846,6 +1846,25 @@ describe('usePress', function () {
expect(document.activeElement).not.toBe(el);
});
+ it('should not throw if the window is focused or blurred during a press', function () {
+ let res = render();
+
+ let el = res.getByText('test');
+ fireEvent.mouseDown(el);
+
+ // preventFocus listens for focus and blur on the window. The browser fires
+ // those at the window itself when it gains or loses focus, e.g. returning
+ // from a native dialog, another tab, or an iframe. The target of those
+ // events is the Window, which is not a Node.
+ fireEvent(window, new FocusEvent('focus'));
+ fireEvent(window, new FocusEvent('blur'));
+
+ fireEvent.mouseUp(el);
+ fireEvent.click(el);
+
+ expect(document.activeElement).not.toBe(el);
+ });
+
it('should focus the element on click by default', function () {
let res = render();