From 862e275a1c150edcefab6d8ba3306192ffd6edfa Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Tue, 21 Jul 2026 10:26:07 +0200 Subject: [PATCH] [DOM] Handle blur on Fragments below `Document` (#37062) Co-authored-by: Claude Fable 5 --- .../src/client/ReactFiberConfigDOM.js | 7 +- .../ReactDOMFragmentRefsDocument-test.js | 68 +++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 packages/react-dom/src/__tests__/ReactDOMFragmentRefsDocument-test.js diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 2ab865cea372..373a9e698e1b 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -3232,8 +3232,11 @@ FragmentInstance.prototype.blur = function (this: FragmentInstanceType): void { const parentInstanceOrContainer = getInstanceFromHostFiber< Instance | Container, >(parentHostFiber); - // TODO: Handle parentInstanceOrContainer being a document - const activeElement = parentInstanceOrContainer.ownerDocument.activeElement; + // Instance is included in the Container type for DOM. + const ownerDocument = getOwnerDocumentFromRootContainer( + parentInstanceOrContainer, + ); + const activeElement = ownerDocument.activeElement; if ( activeElement === null || !parentInstanceOrContainer.contains(activeElement) diff --git a/packages/react-dom/src/__tests__/ReactDOMFragmentRefsDocument-test.js b/packages/react-dom/src/__tests__/ReactDOMFragmentRefsDocument-test.js new file mode 100644 index 000000000000..af8bbc86937d --- /dev/null +++ b/packages/react-dom/src/__tests__/ReactDOMFragmentRefsDocument-test.js @@ -0,0 +1,68 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails reactcore + * @jest-environment node + */ + +'use strict'; + +let JSDOM; +let React; +let ReactDOMClient; +let act; +let document; +let Fragment; + +describe('FragmentRefs', () => { + beforeEach(() => { + jest.resetModules(); + JSDOM = require('jsdom'); + React = require('react'); + Fragment = React.Fragment; + ReactDOMClient = require('react-dom/client'); + act = require('internal-test-utils').act; + + const jsdom = new JSDOM.JSDOM(''); + document = jsdom.window.document; + global.window = jsdom.window; + global.document = global.window.document; + }); + + describe('focus methods', () => { + describe('blur()', () => { + // @gate enableFragmentRefs + it('throws when the nearest host parent is a Document container', async () => { + const fragmentRef = React.createRef(); + const root = ReactDOMClient.createRoot(document); + + await act(() => { + root.render( + + + + + A + + + + , + ); + }); + + await act(() => { + fragmentRef.current.focus(); + }); + expect(document.activeElement.id).toEqual('child-a'); + + await act(() => { + fragmentRef.current.blur(); + }); + expect(document.activeElement).toEqual(document.body); + }); + }); + }); +});