diff --git a/packages/react-dom/src/__tests__/ReactServerRenderingHydration.js b/packages/react-dom/src/__tests__/ReactServerRenderingHydration.js index 721071837aab..054e218367af 100644 --- a/packages/react-dom/src/__tests__/ReactServerRenderingHydration.js +++ b/packages/react-dom/src/__tests__/ReactServerRenderingHydration.js @@ -258,6 +258,67 @@ describe('ReactDOMServerHydration', () => { expect(element.firstChild.focus).not.toHaveBeenCalled(); }); + it('should warn when the style property differs', () => { + const element = document.createElement('div'); + element.innerHTML = ReactDOMServer.renderToString( +
, + ); + expect(element.firstChild.style.textDecoration).toBe('none'); + expect(element.firstChild.style.color).toBe('black'); + + expect(() => + ReactDOM.hydrate( +
, + element, + ), + ).toWarnDev( + 'Warning: Prop `style` did not match. Server: ' + + '"text-decoration:none;color:black;height:10px" Client: ' + + '"text-decoration:none;color:white;height:10px"', + {withoutStack: true}, + ); + }); + + it('should not warn when the style property differs on whitespace or order in IE', () => { + document.documentMode = 11; + const element = document.createElement('div'); + + // Simulate IE normalizing the style attribute. IE makes it equal to + // what's available under `node.style.cssText`. + element.innerHTML = + '
'; + + ReactDOM.hydrate( +
, + element, + ); + + delete document.documentMode; + }); + + it('should warn when the style property differs on whitespace in non-IE browsers', () => { + const element = document.createElement('div'); + + element.innerHTML = + '
'; + + expect(() => + ReactDOM.hydrate( +
, + element, + ), + ).toWarnDev( + 'Warning: Prop `style` did not match. Server: ' + + '"text-decoration: none; color: black; height: 10px;" Client: ' + + '"text-decoration:none;color:black;height:10px"', + {withoutStack: true}, + ); + }); + it('should throw rendering portals on the server', () => { const div = document.createElement('div'); expect(() => { diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index eba71310f41c..35c3d1953824 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -999,12 +999,23 @@ export function diffHydratedProperties( } else if (propKey === STYLE) { // $FlowFixMe - Should be inferred as not undefined. extraAttributeNames.delete(propKey); - const expectedStyle = CSSPropertyOperations.createDangerousStringForStyles( - nextProp, - ); - serverValue = domElement.getAttribute('style'); - if (expectedStyle !== serverValue) { - warnForPropDifference(propKey, serverValue, expectedStyle); + + // IE 11 parses & normalizes the style attribute as opposed to other + // browsers. It adds spaces and sorts the properties in some + // non-alphabetical order. Handling that would require sorting CSS + // properties in the client & server versions or applying + // `expectedStyle` to a temporary DOM node to read its `style` attribute + // normalized. Since it only affects IE, we're skipping style warnings + // in that browser completely in favor of doing all that work. + // See https://github.com/facebook/react/issues/11807 + if (!document.documentMode) { + const expectedStyle = CSSPropertyOperations.createDangerousStringForStyles( + nextProp, + ); + serverValue = domElement.getAttribute('style'); + if (expectedStyle !== serverValue) { + warnForPropDifference(propKey, serverValue, expectedStyle); + } } } else if (isCustomComponentTag) { // $FlowFixMe - Should be inferred as not undefined.