diff --git a/packages/react-dom-bindings/src/shared/DOMProperty.js b/packages/react-dom-bindings/src/shared/DOMProperty.js index 9e7b7bf6771b5..44a6eee22ba7a 100644 --- a/packages/react-dom-bindings/src/shared/DOMProperty.js +++ b/packages/react-dom-bindings/src/shared/DOMProperty.js @@ -636,7 +636,19 @@ properties[xlinkHref] = new PropertyInfoRecord( false, // removeEmptyString ); -['src', 'href', 'action', 'formAction'].forEach(attributeName => { +const formAction = 'formAction'; +// $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions +properties[formAction] = new PropertyInfoRecord( + 'formAction', + STRING, + false, // mustUseProperty + 'formaction', // attributeName + null, // attributeNamespace + true, // sanitizeURL + false, // removeEmptyString +); + +['src', 'href', 'action'].forEach(attributeName => { // $FlowFixMe[invalid-constructor] Flow no longer supports calling new on functions properties[attributeName] = new PropertyInfoRecord( attributeName, diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index e0fe178d2fe8c..c4d4204d30590 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -533,29 +533,17 @@ describe('ReactDOMComponent', () => { expect(node.hasAttribute('action')).toBe(false); }); - it('should not add an empty formAction attribute', () => { + it('allows empty string of a formAction to override the default of a parent', () => { const container = document.createElement('div'); - expect(() => - ReactDOM.render(, container), - ).toErrorDev( - 'An empty string ("") was passed to the formAction attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to formAction instead of an empty string.', - ); - const node = container.firstChild; - expect(node.hasAttribute('formAction')).toBe(false); - - ReactDOM.render(, container); - expect(node.hasAttribute('formAction')).toBe(true); - - expect(() => - ReactDOM.render(, container), - ).toErrorDev( - 'An empty string ("") was passed to the formAction attribute. ' + - 'To fix this, either do not render the element at all ' + - 'or pass null to formAction instead of an empty string.', + ReactDOM.render( +
, + container, ); - expect(node.hasAttribute('formAction')).toBe(false); + const node = container.firstChild.firstChild; + expect(node.hasAttribute('formaction')).toBe(true); + expect(node.getAttribute('formaction')).toBe(''); }); it('should not filter attributes for custom elements', () => { diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index 958c2e845922a..1bba854339b98 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -172,7 +172,7 @@ export const disableInputAttributeSyncing = false; // Filter certain DOM attributes (e.g. src, href) if their values are empty // strings. This prevents e.g. from making an unnecessary HTTP // request for certain browsers. -export const enableFilterEmptyStringAttributesDOM = false; +export const enableFilterEmptyStringAttributesDOM = __EXPERIMENTAL__; // Changes the behavior for rendering custom elements in both server rendering // and client rendering, mostly to allow JSX attributes to apply to the custom