From 23110f40cf0ffa4a75200e7f21a44accb6b30af2 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 26 Jan 2026 15:48:18 -0500 Subject: [PATCH 1/3] Use parent to bail out of blur() traversal --- .../src/client/ReactFiberConfigDOM.js | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 09653552aaf..9754210e65f 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3154,18 +3154,34 @@ function collectChildren(child: Fiber, collection: Array): boolean { } // $FlowFixMe[prop-missing] FragmentInstance.prototype.blur = function (this: FragmentInstanceType): void { - // TODO: When we have a parent element reference, we can skip traversal if the fragment's parent - // does not contain document.activeElement + // Early exit if activeElement is not within the fragment's parent + const parentHostFiber = getFragmentParentHostFiber(this._fragmentFiber); + if (parentHostFiber === null) { + return; + } + const parentHostInstance = + getInstanceFromHostFiber(parentHostFiber); + const activeElement = parentHostInstance.ownerDocument.activeElement; + if (activeElement === null || !parentHostInstance.contains(activeElement)) { + return; + } + traverseFragmentInstance( this._fragmentFiber, blurActiveElementWithinFragment, + activeElement, ); }; -function blurActiveElementWithinFragment(child: Fiber): boolean { - // TODO: We can get the activeElement from the parent outside of the loop when we have a reference. +function blurActiveElementWithinFragment( + child: Fiber, + activeElement: Element, +): boolean { + // Skip text nodes - they can't be focused + if (enableFragmentRefsTextNodes && child.tag === HostText) { + return false; + } const instance = getInstanceFromHostFiber(child); - const ownerDocument = instance.ownerDocument; - if (instance === ownerDocument.activeElement) { + if (instance === activeElement) { // $FlowFixMe[prop-missing] instance.blur(); return true; From 8d6c88d62c3f1efbcdd4acd41d246c9fcf9b7a07 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 26 Jan 2026 15:52:49 -0500 Subject: [PATCH 2/3] Extract event normalization from loop --- packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 9754210e65f..5acf652a854 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3056,13 +3056,13 @@ function indexOfEventListener( listener: EventListener, optionsOrUseCapture: void | EventListenerOptionsOrUseCapture, ): number { + const normalizedOptions = normalizeListenerOptions(optionsOrUseCapture); for (let i = 0; i < eventListeners.length; i++) { const item = eventListeners[i]; if ( item.type === type && item.listener === listener && - normalizeListenerOptions(item.optionsOrUseCapture) === - normalizeListenerOptions(optionsOrUseCapture) + normalizeListenerOptions(item.optionsOrUseCapture) === normalizedOptions ) { return i; } From 4fd0d40363889af75c89bcdbb331795afc1c5d87 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Mon, 26 Jan 2026 15:54:00 -0500 Subject: [PATCH 3/3] Improve var naming element->node --- .../src/client/ReactFiberConfigDOM.js | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 5acf652a854..1fdb4192d7b 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3328,46 +3328,45 @@ FragmentInstance.prototype.compareDocumentPosition = function ( ); } - const firstElement = getInstanceFromHostFiber(children[0]); - const lastElement = getInstanceFromHostFiber( + const firstNode = getInstanceFromHostFiber(children[0]); + const lastNode = getInstanceFromHostFiber( children[children.length - 1], ); // If the fragment has been portaled into another host instance, we need to // our best guess is to use the parent of the child instance, rather than // the fiber tree host parent. - const firstInstance = getInstanceFromHostFiber(children[0]); const parentHostInstanceFromDOM = fiberIsPortaledIntoHost(this._fragmentFiber) - ? (firstInstance.parentElement: ?Instance) + ? (firstNode.parentElement: ?Instance) : parentHostInstance; if (parentHostInstanceFromDOM == null) { return Node.DOCUMENT_POSITION_DISCONNECTED; } - // Check if first and last element are actually in the expected document position - // before relying on them as source of truth for other contained elements - const firstElementIsContained = - parentHostInstanceFromDOM.compareDocumentPosition(firstElement) & + // Check if first and last node are actually in the expected document position + // before relying on them as source of truth for other contained nodes + const firstNodeIsContained = + parentHostInstanceFromDOM.compareDocumentPosition(firstNode) & Node.DOCUMENT_POSITION_CONTAINED_BY; - const lastElementIsContained = - parentHostInstanceFromDOM.compareDocumentPosition(lastElement) & + const lastNodeIsContained = + parentHostInstanceFromDOM.compareDocumentPosition(lastNode) & Node.DOCUMENT_POSITION_CONTAINED_BY; - const firstResult = firstElement.compareDocumentPosition(otherNode); - const lastResult = lastElement.compareDocumentPosition(otherNode); + const firstResult = firstNode.compareDocumentPosition(otherNode); + const lastResult = lastNode.compareDocumentPosition(otherNode); const otherNodeIsFirstOrLastChild = - (firstElementIsContained && firstElement === otherNode) || - (lastElementIsContained && lastElement === otherNode); + (firstNodeIsContained && firstNode === otherNode) || + (lastNodeIsContained && lastNode === otherNode); const otherNodeIsFirstOrLastChildDisconnected = - (!firstElementIsContained && firstElement === otherNode) || - (!lastElementIsContained && lastElement === otherNode); + (!firstNodeIsContained && firstNode === otherNode) || + (!lastNodeIsContained && lastNode === otherNode); const otherNodeIsWithinFirstOrLastChild = firstResult & Node.DOCUMENT_POSITION_CONTAINED_BY || lastResult & Node.DOCUMENT_POSITION_CONTAINED_BY; const otherNodeIsBetweenFirstAndLastChildren = - firstElementIsContained && - lastElementIsContained && + firstNodeIsContained && + lastNodeIsContained && firstResult & Node.DOCUMENT_POSITION_FOLLOWING && lastResult & Node.DOCUMENT_POSITION_PRECEDING;