From b48e739998432fc9672a42d0d04515980b8cae82 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Thu, 6 Feb 2025 14:30:41 -0800 Subject: [PATCH 1/2] [Fiber] `getHoistableRoot()` should account for Document containers (#32321) While modern DOM implementations all support getRootNode if you are running React in a runtime which does not the fallback logic which uses `.ownerDocument` works everywhere except when the container is a Document itself. This change corrects this by returning the container intsance if it is a Document type. --- .../react-dom-bindings/src/client/ReactFiberConfigDOM.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js index 90c3855379f..012f7cd257f 100644 --- a/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js +++ b/packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js @@ -2523,10 +2523,13 @@ export type HoistableRoot = Document | ShadowRoot; export function getHoistableRoot(container: Container): HoistableRoot { // $FlowFixMe[method-unbinding] return typeof container.getRootNode === 'function' - ? /* $FlowFixMe[incompatible-return] Flow types this as returning a `Node`, + ? /* $FlowFixMe[incompatible-cast] Flow types this as returning a `Node`, * but it's either a `Document` or `ShadowRoot`. */ - container.getRootNode() - : container.ownerDocument; + (container.getRootNode(): Document | ShadowRoot) + : container.nodeType === DOCUMENT_NODE + ? // $FlowFixMe[incompatible-cast] We've constrained this to be a Document which satisfies the return type + (container: Document) + : container.ownerDocument; } function getCurrentResourceRoot(): null | HoistableRoot { From a0fdb6306043b9f049106e58dcec107d8dbed2b1 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Thu, 6 Feb 2025 15:05:51 -0800 Subject: [PATCH 2/2] [Fiber][Dev] Relax dom nesting validation when the root is a Document, html tag, or body tag (#32252) followup to * https://github.com/facebook/react/pull/32069 * https://github.com/facebook/react/pull/32163 * https://github.com/facebook/react/pull/32224 in react-dom in Dev we validate that the tag nesting is valid. This is motivated primarily because while browsers are tolerant to poor HTML there are many cases that if server rendered will be hydrated in a way that will break hydration. With the changes to singleton scoping where the document body is now the implicit render/hydration context for arbitrary tags at the root we need to adjust the validation logic to allow for valid programs such as rendering divs as a child of a Document (since this div will actually insert into the body). --- .../src/client/ReactDOMComponent.js | 4 +- .../src/client/ReactFiberConfigDOM.js | 23 +++- .../src/client/validateDOMNesting.js | 72 ++++++++++-- .../react-dom/src/__tests__/ReactDOM-test.js | 12 -- .../src/__tests__/ReactDOMFizzServer-test.js | 2 - .../src/__tests__/ReactDOMFloat-test.js | 6 - .../src/__tests__/validateDOMNesting-test.js | 105 +++++++++++++++--- 7 files changed, 175 insertions(+), 49 deletions(-) diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index 6406b734c43..15a4ba675b5 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -344,7 +344,7 @@ function setProp( case 'children': { if (typeof value === 'string') { if (__DEV__) { - validateTextNesting(value, tag); + validateTextNesting(value, tag, false); } // Avoid setting initial textContent when the text is empty. In IE11 setting // textContent on a