diff --git a/README.md b/README.md
index 46a9d595fb..163a8c71ea 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,7 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
* [react/forbid-component-props](docs/rules/forbid-component-props.md): Forbid certain props on Components
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
* [react/no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
+* [react/no-danger-with-children](docs/rules/no-danger-with-children.md): Prevent problem with children and props.dangerouslySetInnerHTML
* [react/no-deprecated](docs/rules/no-deprecated.md): Prevent usage of deprecated methods
* [react/no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of `setState` in `componentDidMount`
* [react/no-did-update-set-state](docs/rules/no-did-update-set-state.md): Prevent usage of `setState` in `componentDidUpdate`
diff --git a/docs/rules/no-danger-with-children.md b/docs/rules/no-danger-with-children.md
new file mode 100644
index 0000000000..bb21a035dc
--- /dev/null
+++ b/docs/rules/no-danger-with-children.md
@@ -0,0 +1,53 @@
+# Prevent problem with children and props.dangerouslySetInnerHTML (no-danger-with-children)
+
+This rule helps prevent problems caused by using children and the dangerouslySetInnerHTML prop at the same time.
+React will throw a warning if this rule is ignored.
+
+## Rule Details
+
+The following patterns are considered warnings:
+
+```jsx
+
+ Children
+
+
+
+ Children
+
+
+```
+
+```js
+React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } }, "Children");
+
+React.createElement("Hello", { dangerouslySetInnerHTML: { __html: "HTML" } }, "Children");
+```
+
+The following patterns are not considered warnings:
+
+```jsx
+
+
+
+
+
+ Children
+
+
+
+ Children
+
+
+```
+
+```js
+React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } });
+
+React.createElement("Hello", { dangerouslySetInnerHTML: { __html: "HTML" } });
+
+React.createElement("div", {}, "Children");
+
+React.createElement("Hello", {}, "Children");
+```
+
diff --git a/index.js b/index.js
index 0a25847325..88ab4dcb6c 100644
--- a/index.js
+++ b/index.js
@@ -53,7 +53,8 @@ var rules = {
'jsx-no-target-blank': require('./lib/rules/jsx-no-target-blank'),
'jsx-filename-extension': require('./lib/rules/jsx-filename-extension'),
'require-optimization': require('./lib/rules/require-optimization'),
- 'no-find-dom-node': require('./lib/rules/no-find-dom-node')
+ 'no-find-dom-node': require('./lib/rules/no-find-dom-node'),
+ 'no-danger-with-children': require('./lib/rules/no-danger-with-children')
};
var ruleNames = Object.keys(rules);
diff --git a/lib/rules/no-danger-with-children.js b/lib/rules/no-danger-with-children.js
new file mode 100644
index 0000000000..c9deb368cd
--- /dev/null
+++ b/lib/rules/no-danger-with-children.js
@@ -0,0 +1,80 @@
+/**
+ * @fileoverview Report when a DOM element is using both children and dangerouslySetInnerHTML
+ * @author David Petersen
+ */
+'use strict';
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+module.exports = {
+ meta: {
+ docs: {
+ description: 'Report when a DOM element is using both children and dangerouslySetInnerHTML',
+ category: '',
+ recommended: false
+ },
+ schema: [] // no options
+ },
+ create: function(context) {
+ return {
+ JSXElement: function (node) {
+ var hasChildren = false;
+ var attributes = node.openingElement.attributes;
+
+ if (node.children.length) {
+ hasChildren = true;
+ } else {
+ var childrenProp = attributes.find(function (attribute) {
+ return attribute.name.name === 'children';
+ });
+ if (childrenProp) {
+ hasChildren = true;
+ }
+ }
+
+ if (attributes && hasChildren) {
+ var jsxElement = attributes.find(function (attribute) {
+ return attribute.name.name === 'dangerouslySetInnerHTML';
+ });
+
+
+ if (jsxElement) {
+ context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
+ }
+ }
+ },
+ CallExpression: function (node) {
+ if (
+ node.callee
+ && node.callee.type === 'MemberExpression'
+ && node.callee.property.name === 'createElement'
+ && node.arguments.length > 1
+ ) {
+ var hasChildren = false;
+
+ var props = node.arguments[1].properties;
+ var dangerously = props.find(function(prop) {
+ return prop.key.name === 'dangerouslySetInnerHTML';
+ });
+
+
+ if (node.arguments.length === 2) {
+ var childrenProp = props.find(function(prop) {
+ return prop.key.name === 'children';
+ });
+ if (childrenProp) {
+ hasChildren = true;
+ }
+ } else {
+ hasChildren = true;
+ }
+
+ if (dangerously && hasChildren) {
+ context.report(node, 'Only set one of `children` or `props.dangerouslySetInnerHTML`');
+ }
+ }
+ }
+ };
+ }
+};
diff --git a/tests/lib/rules/no-danger-with-children.js b/tests/lib/rules/no-danger-with-children.js
new file mode 100644
index 0000000000..a44124bc50
--- /dev/null
+++ b/tests/lib/rules/no-danger-with-children.js
@@ -0,0 +1,139 @@
+/**
+ * @fileoverview Report when a DOM element is using both children and dangerouslySetInnerHTML
+ * @author David Petersen
+ */
+'use strict';
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+var rule = require('../../../lib/rules/no-danger-with-children');
+var RuleTester = require('eslint').RuleTester;
+
+var parserOptions = {
+ ecmaVersion: 6,
+ ecmaFeatures: {
+ jsx: true
+ }
+};
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+var ruleTester = new RuleTester();
+ruleTester.run('no-danger-with-children', rule, {
+ valid: [
+ {
+ code: 'Children
',
+ parserOptions: parserOptions
+ },
+ {
+ code: '',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'Children',
+ parserOptions: parserOptions
+ },
+ {
+ code: '',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", { dangerouslySetInnerHTML: { __html: "HTML" } });',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {}, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("Hello", { dangerouslySetInnerHTML: { __html: "HTML" } });',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("Hello", {}, "Children");',
+ parserOptions: parserOptions
+ }
+ ],
+ invalid: [
+ {
+ code: [
+ '',
+ ' Children',
+ '
'
+ ].join('\n'),
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: '',
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: [
+ '',
+ ' Children',
+ ''
+ ].join('\n'),
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: '',
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: [
+ 'React.createElement(',
+ ' "div",',
+ ' { dangerouslySetInnerHTML: { __html: "HTML" } },',
+ ' "Children"',
+ ');'
+ ].join('\n'),
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: [
+ 'React.createElement(',
+ ' "div",',
+ ' {',
+ ' dangerouslySetInnerHTML: { __html: "HTML" },',
+ ' children: "Children",',
+ ' }',
+ ');'
+ ].join('\n'),
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: [
+ 'React.createElement(',
+ ' "Hello",',
+ ' { dangerouslySetInnerHTML: { __html: "HTML" } },',
+ ' "Children"',
+ ');'
+ ].join('\n'),
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ },
+ {
+ code: [
+ 'React.createElement(',
+ ' "Hello",',
+ ' {',
+ ' dangerouslySetInnerHTML: { __html: "HTML" },',
+ ' children: "Children",',
+ ' }',
+ ');'
+ ].join('\n'),
+ errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}],
+ parserOptions: parserOptions
+ }
+ ]
+});