Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Warn when the string "false" is the value of a boolean DOM prop
  • Loading branch information
motiz88 committed Aug 11, 2018
commit 1447508e58060942e2224c623b40765b12933e78
26 changes: 26 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2506,6 +2506,32 @@ describe('ReactDOMComponent', () => {
});
});

describe('Boolean attributes', function() {
it('warns on the ambiguous string value "false"', function() {
let el;
expect(() => {
el = ReactTestUtils.renderIntoDocument(<div hidden="false" />);
}).toWarnDev(
'Received the string `false` for the boolean attribute `hidden`. ' +
'Did you mean hidden={false}?',
);

expect(el.getAttribute('hidden')).toBe('');
});

it('warns on the ambiguous string value "False"', function() {
let el;
expect(() => {
el = ReactTestUtils.renderIntoDocument(<div hidden="False" />);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since title case False doesn’t have special meaning I don’t think it’s worth testing for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to take your steer on this, I'd just like to state my case first for completeness: The thing I was trying to make safer was people drawing inferences from one "boolean" HTML attribute to another. Since enumerated attribute values are case-insensitive, spellCheck="False" does behave differently to hidden="False", in exactly the same way as the respective lowercase variants do. I take your point that most people would be using lowercase to begin with, so this is probably a rarer case, but it does theoretically occur.

To clarify, you're referring to dropping the toLowerCase() in the actual check, as well as removing this test, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I see your point but I think it's unlikely enough to be written accidentally and we want to make the checks as cheap as possible. Strict comparison is better than extra toLowerCase call.

}).toWarnDev(
'Received the string `False` for the boolean attribute `hidden`. ' +
'Did you mean hidden={false}?',
);

expect(el.getAttribute('hidden')).toBe('');
});
});

describe('Hyphenated SVG elements', function() {
it('the font-face element is not a custom element', function() {
let el;
Expand Down
20 changes: 20 additions & 0 deletions packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import warning from 'shared/warning';

import {
ATTRIBUTE_NAME_CHAR,
BOOLEAN,
RESERVED,
shouldRemoveAttributeWithWarning,
getPropertyInfo,
Expand Down Expand Up @@ -226,6 +227,25 @@ if (__DEV__) {
return false;
}

// Warn when passing the string 'false' into a boolean prop
if (
propertyInfo !== null &&
propertyInfo.type === BOOLEAN &&
typeof value === 'string' &&
value.toLowerCase() === 'false'
) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let’s make value === 'false' the first condition. Since it’s rare we won’t have to check most other conditions.

warning(
false,
'Received the string `%s` for the boolean attribute `%s`. ' +
'Did you mean %s={false}?',
value,
name,
name,
);
warnedProperties[name] = true;
return true;
}

return true;
};
}
Expand Down