diff --git a/packages/react-dom-bindings/src/client/ReactDOMComponent.js b/packages/react-dom-bindings/src/client/ReactDOMComponent.js index ac95c91c596a8..05892c930e1ca 100644 --- a/packages/react-dom-bindings/src/client/ReactDOMComponent.js +++ b/packages/react-dom-bindings/src/client/ReactDOMComponent.js @@ -63,10 +63,7 @@ import {validateProperties as validateInputProperties} from '../shared/ReactDOMN import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook'; import sanitizeURL from '../shared/sanitizeURL'; -import { - enableTrustedTypesIntegration, - enableFilterEmptyStringAttributesDOM, -} from 'shared/ReactFeatureFlags'; +import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags'; import { mediaEventTypes, listenToNonDelegatedEvent, @@ -400,35 +397,33 @@ function setProp( // fallthrough case 'src': case 'href': { - if (enableFilterEmptyStringAttributesDOM) { - if ( - value === '' && - // is fine for "reload" links. - !(tag === 'a' && key === 'href') - ) { - if (__DEV__) { - if (key === 'src') { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'This may cause the browser to download the whole page again over the network. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - key, - key, - ); - } else { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - key, - key, - ); - } + if ( + value === '' && + // is fine for "reload" links. + !(tag === 'a' && key === 'href') + ) { + if (__DEV__) { + if (key === 'src') { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'This may cause the browser to download the whole page again over the network. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + key, + key, + ); + } else { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + key, + key, + ); } - domElement.removeAttribute(key); - break; } + domElement.removeAttribute(key); + break; } if ( value == null || @@ -2489,53 +2484,52 @@ function diffHydratedGenericElement( // fallthrough case 'src': case 'href': - if (enableFilterEmptyStringAttributesDOM) { - if ( - value === '' && - // is fine for "reload" links. - !(tag === 'a' && propKey === 'href') && - !(tag === 'object' && propKey === 'data') - ) { - if (__DEV__) { - if (propKey === 'src') { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'This may cause the browser to download the whole page again over the network. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - propKey, - propKey, - ); - } else { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - propKey, - propKey, - ); - } + if ( + value === '' && + // is fine for "reload" links. + !(tag === 'a' && propKey === 'href') && + !(tag === 'object' && propKey === 'data') + ) { + if (__DEV__) { + if (propKey === 'src') { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'This may cause the browser to download the whole page again over the network. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + propKey, + propKey, + ); + } else { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + propKey, + propKey, + ); } - hydrateSanitizedAttribute( - domElement, - propKey, - propKey, - null, - extraAttributes, - serverDifferences, - ); - continue; } + hydrateSanitizedAttribute( + domElement, + propKey, + propKey, + null, + extraAttributes, + serverDifferences, + ); + continue; + } else { + hydrateSanitizedAttribute( + domElement, + propKey, + propKey, + value, + extraAttributes, + serverDifferences, + ); + continue; } - hydrateSanitizedAttribute( - domElement, - propKey, - propKey, - value, - extraAttributes, - serverDifferences, - ); - continue; case 'action': case 'formAction': { const serverValue = domElement.getAttribute(propKey); diff --git a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js index 1351a28db3aab..fe2e713d8a3ba 100644 --- a/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js +++ b/packages/react-dom-bindings/src/server/ReactFizzConfigDOM.js @@ -27,10 +27,7 @@ import { import {Children} from 'react'; -import { - enableFilterEmptyStringAttributesDOM, - enableFizzExternalRuntime, -} from 'shared/ReactFeatureFlags'; +import {enableFizzExternalRuntime} from 'shared/ReactFeatureFlags'; import type { Destination, @@ -1210,30 +1207,28 @@ function pushAttribute( } case 'src': case 'href': { - if (enableFilterEmptyStringAttributesDOM) { - if (value === '') { - if (__DEV__) { - if (name === 'src') { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'This may cause the browser to download the whole page again over the network. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - name, - name, - ); - } else { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - name, - name, - ); - } + if (value === '') { + if (__DEV__) { + if (name === 'src') { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'This may cause the browser to download the whole page again over the network. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + name, + name, + ); + } else { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + name, + name, + ); } - return; } + return; } } // Fall through to the last case which shouldn't remove empty strings. @@ -1633,19 +1628,17 @@ function pushStartObject( checkAttributeStringCoercion(propValue, 'data'); } const sanitizedValue = sanitizeURL('' + propValue); - if (enableFilterEmptyStringAttributesDOM) { - if (sanitizedValue === '') { - if (__DEV__) { - console.error( - 'An empty string ("") was passed to the %s attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to %s instead of an empty string.', - propKey, - propKey, - ); - } - break; + if (sanitizedValue === '') { + if (__DEV__) { + console.error( + 'An empty string ("") was passed to the %s attribute. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to %s instead of an empty string.', + propKey, + propKey, + ); } + break; } target.push( attributeSeparator, @@ -3615,11 +3608,7 @@ export function pushStartInstance( // Fast track very common tags break; case 'a': - if (enableFilterEmptyStringAttributesDOM) { - return pushStartAnchor(target, props); - } else { - break; - } + return pushStartAnchor(target, props); case 'g': case 'p': case 'li': diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index d37a4ecba6dc6..ce71a6334ee64 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -587,133 +587,131 @@ describe('ReactDOMComponent', () => { expect(node.hasAttribute('data-foo')).toBe(false); }); - if (ReactFeatureFlags.enableFilterEmptyStringAttributesDOM) { - it('should not add an empty src attribute', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'An empty string ("") was passed to the src attribute. ' + - 'This may cause the browser to download the whole page again over the network. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to src instead of an empty string.', - ); - const node = container.firstChild; - expect(node.hasAttribute('src')).toBe(false); - + it('should not add an empty src attribute', async () => { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await expect(async () => { await act(() => { - root.render(); + root.render(); }); - expect(node.hasAttribute('src')).toBe(true); + }).toErrorDev( + 'An empty string ("") was passed to the src attribute. ' + + 'This may cause the browser to download the whole page again over the network. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to src instead of an empty string.', + ); + const node = container.firstChild; + expect(node.hasAttribute('src')).toBe(false); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'An empty string ("") was passed to the src attribute. ' + - 'This may cause the browser to download the whole page again over the network. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to src instead of an empty string.', - ); - expect(node.hasAttribute('src')).toBe(false); + await act(() => { + root.render(); }); + expect(node.hasAttribute('src')).toBe(true); - it('should not add an empty href attribute', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'An empty string ("") was passed to the href attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to href instead of an empty string.', - ); - const node = container.firstChild; - expect(node.hasAttribute('href')).toBe(false); + await expect(async () => { + await act(() => { + root.render(); + }); + }).toErrorDev( + 'An empty string ("") was passed to the src attribute. ' + + 'This may cause the browser to download the whole page again over the network. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to src instead of an empty string.', + ); + expect(node.hasAttribute('src')).toBe(false); + }); + it('should not add an empty href attribute', async () => { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await expect(async () => { await act(() => { - root.render(); + root.render(); }); - expect(node.hasAttribute('href')).toBe(true); + }).toErrorDev( + 'An empty string ("") was passed to the href attribute. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to href instead of an empty string.', + ); + const node = container.firstChild; + expect(node.hasAttribute('href')).toBe(false); - await expect(async () => { - await act(() => { - root.render(); - }); - }).toErrorDev( - 'An empty string ("") was passed to the href attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to href instead of an empty string.', - ); - expect(node.hasAttribute('href')).toBe(false); + await act(() => { + root.render(); }); + expect(node.hasAttribute('href')).toBe(true); - it('should allow an empty href attribute on anchors', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); + await expect(async () => { await act(() => { - root.render(); + root.render(); }); - const node = container.firstChild; - expect(node.getAttribute('href')).toBe(''); + }).toErrorDev( + 'An empty string ("") was passed to the href attribute. ' + + 'To fix this, either do not render the element at all ' + + 'or pass null to href instead of an empty string.', + ); + expect(node.hasAttribute('href')).toBe(false); + }); + + it('should allow an empty href attribute on anchors', async () => { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); }); + const node = container.firstChild; + expect(node.getAttribute('href')).toBe(''); + }); - it('should allow an empty action attribute', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render(
); - }); - const node = container.firstChild; - expect(node.getAttribute('action')).toBe(''); + it('should allow an empty action attribute', async () => { + const container = document.createElement('div'); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + const node = container.firstChild; + expect(node.getAttribute('action')).toBe(''); - await act(() => { - root.render(); - }); - expect(node.hasAttribute('action')).toBe(true); + await act(() => { + root.render(); + }); + expect(node.hasAttribute('action')).toBe(true); - await act(() => { - root.render(); - }); - expect(node.getAttribute('action')).toBe(''); + await act(() => { + root.render(); }); + expect(node.getAttribute('action')).toBe(''); + }); - it('allows empty string of a formAction to override the default of a parent', async () => { - const container = document.createElement('div'); - const root = ReactDOMClient.createRoot(container); - await act(() => { - root.render( - -