diff --git a/src/browser/ui/ReactDOMComponent.js b/src/browser/ui/ReactDOMComponent.js
index 0a6f60e14ac..3d7031f13bf 100644
--- a/src/browser/ui/ReactDOMComponent.js
+++ b/src/browser/ui/ReactDOMComponent.js
@@ -27,6 +27,7 @@ var invariant = require('invariant');
var isEventSupported = require('isEventSupported');
var keyOf = require('keyOf');
var monitorCodeUse = require('monitorCodeUse');
+var warning = require('warning');
var deleteListener = ReactBrowserEventEmitter.deleteListener;
var listenTo = ReactBrowserEventEmitter.listenTo;
@@ -52,11 +53,23 @@ function assertValidProps(props) {
return;
}
// Note the use of `==` which checks for null or undefined.
- invariant(
- props.children == null || props.dangerouslySetInnerHTML == null,
- 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
- );
+ if (props.dangerouslySetInnerHTML != null) {
+ invariant(
+ props.children == null,
+ 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+ );
+ invariant(
+ props.dangerouslySetInnerHTML.__html != null,
+ '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
+ 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+ );
+ }
if (__DEV__) {
+ warning(
+ props.innerHTML == null,
+ 'Directly setting property `innerHTML` is not permitted. ' +
+ 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+ );
if (props.contentEditable && props.children != null) {
console.warn(
'A component is `contentEditable` and contains `children` managed by ' +
diff --git a/src/browser/ui/__tests__/ReactDOMComponent-test.js b/src/browser/ui/__tests__/ReactDOMComponent-test.js
index aa557c662d2..b69773cd241 100644
--- a/src/browser/ui/__tests__/ReactDOMComponent-test.js
+++ b/src/browser/ui/__tests__/ReactDOMComponent-test.js
@@ -341,6 +341,36 @@ describe('ReactDOMComponent', function() {
);
});
+ it('should validate against use of innerHTML', function() {
+
+ spyOn(console, 'warn');
+ mountComponent({ innerHTML: 'Hi Jim!' });
+ expect(console.warn.argsForCall.length).toBe(1);
+ expect(console.warn.argsForCall[0][0]).toContain(
+ 'Directly setting property `innerHTML` is not permitted. '
+ );
+ });
+
+ it('should validate use of dangerouslySetInnerHTML', function() {
+ expect(function() {
+ mountComponent({ dangerouslySetInnerHTML: 'Hi Jim!' });
+ }).toThrow(
+ 'Invariant Violation: ' +
+ '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
+ 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+ );
+ });
+
+ it('should validate use of dangerouslySetInnerHTML', function() {
+ expect(function() {
+ mountComponent({ dangerouslySetInnerHTML: {foo: 'bar'} });
+ }).toThrow(
+ 'Invariant Violation: ' +
+ '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
+ 'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+ );
+ });
+
it("should warn about contentEditable and children", function() {
spyOn(console, 'warn');
mountComponent({ contentEditable: true, children: '' });