diff --git a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js index 642c5834c881b..b83ce5d5e1f36 100644 --- a/packages/react-dom/src/__tests__/ReactDOMComponent-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMComponent-test.js @@ -2506,6 +2506,34 @@ describe('ReactDOMComponent', () => { }); }); + describe('Boolean attributes', function() { + it('warns on the ambiguous string value "false"', function() { + let el; + expect(() => { + el = ReactTestUtils.renderIntoDocument(
); + }).toWarnDev( + 'Received the string `false` for the boolean attribute `hidden`. ' + + 'The browser will interpret it as a truthy value. ' + + 'Did you mean hidden={false}?', + ); + + expect(el.getAttribute('hidden')).toBe(''); + }); + + it('warns on the potentially-ambiguous string value "true"', function() { + let el; + expect(() => { + el = ReactTestUtils.renderIntoDocument(); + }).toWarnDev( + 'Received the string `true` for the boolean attribute `hidden`. ' + + 'Although this works, it will not work as expected if you pass the string "false". ' + + 'Did you mean hidden={true}?', + ); + + expect(el.getAttribute('hidden')).toBe(''); + }); + }); + describe('Hyphenated SVG elements', function() { it('the font-face element is not a custom element', function() { let el; diff --git a/packages/react-dom/src/__tests__/ReactDOMInput-test.js b/packages/react-dom/src/__tests__/ReactDOMInput-test.js index 5afa9dcf7aaf4..b21931cb53b02 100644 --- a/packages/react-dom/src/__tests__/ReactDOMInput-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMInput-test.js @@ -444,7 +444,7 @@ describe('ReactDOMInput', () => { it('should take `defaultValue` when changing to uncontrolled input', () => { const node = ReactDOM.render( - , + , container, ); expect(node.value).toBe('0'); diff --git a/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js b/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js index 9e7fda4e6cd8d..3c42172f9eac5 100644 --- a/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js +++ b/packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js @@ -13,6 +13,7 @@ import warning from 'shared/warning'; import { ATTRIBUTE_NAME_CHAR, + BOOLEAN, RESERVED, shouldRemoveAttributeWithWarning, getPropertyInfo, @@ -226,6 +227,29 @@ if (__DEV__) { return false; } + // Warn when passing the strings 'false' or 'true' into a boolean prop + if ( + (value === 'false' || value === 'true') && + propertyInfo !== null && + propertyInfo.type === BOOLEAN + ) { + warning( + false, + 'Received the string `%s` for the boolean attribute `%s`. ' + + '%s ' + + 'Did you mean %s={%s}?', + value, + name, + value === 'false' + ? 'The browser will interpret it as a truthy value.' + : 'Although this works, it will not work as expected if you pass the string "false".', + name, + value, + ); + warnedProperties[name] = true; + return true; + } + return true; }; }