diff --git a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js index 9c82cb6579231..99cb6db2a12b6 100644 --- a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js +++ b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js @@ -3134,32 +3134,13 @@ function pushStartCustomElement( let children = null; let innerHTML = null; - for (let propKey in props) { + for (const propKey in props) { if (hasOwnProperty.call(props, propKey)) { let propValue = props[propKey]; if (propValue == null) { continue; } - if ( - enableCustomElementPropertySupport && - (typeof propValue === 'function' || typeof propValue === 'object') - ) { - // It is normal to render functions and objects on custom elements when - // client rendering, but when server rendering the output isn't useful, - // so skip it. - continue; - } - if (enableCustomElementPropertySupport && propValue === false) { - continue; - } - if (enableCustomElementPropertySupport && propValue === true) { - propValue = ''; - } - if (enableCustomElementPropertySupport && propKey === 'className') { - // className gets rendered as class on the client, so it should be - // rendered as class on the server. - propKey = 'class'; - } + let attributeName = propKey; switch (propKey) { case 'children': children = propValue; @@ -3174,15 +3155,31 @@ function pushStartCustomElement( case 'suppressHydrationWarning': // Ignored. These are built-in to React on the client. break; + case 'className': + if (enableCustomElementPropertySupport) { + // className gets rendered as class on the client, so it should be + // rendered as class on the server. + attributeName = 'class'; + } + // intentional fallthrough default: if ( isAttributeNameSafe(propKey) && typeof propValue !== 'function' && typeof propValue !== 'symbol' ) { + if (enableCustomElementPropertySupport) { + if (propValue === false) { + continue; + } else if (propValue === true) { + propValue = ''; + } else if (typeof propValue === 'object') { + continue; + } + } target.push( attributeSeparator, - stringToChunk(propKey), + stringToChunk(attributeName), attributeAssign, stringToChunk(escapeTextForBrowser(propValue)), attributeEnd, diff --git a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js index a873a257528c5..5d9c8bcaeccc4 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js @@ -3624,6 +3624,32 @@ describe('ReactDOMFizzServer', () => { ); }); + // bugfix: https://github.com/facebook/react/issues/27286 affecting enableCustomElementPropertySupport flag + it('can render custom elements with children on ther server', async () => { + await act(() => { + renderToPipeableStream( + + + +
foo
+
+ + , + ).pipe(writable); + }); + + expect(getVisibleChildren(document)).toEqual( + + + + +
foo
+
+ + , + ); + }); + describe('error escaping', () => { it('escapes error hash, message, and component stack values in directly flushed errors (html escaping)', async () => { window.__outlet = {};