diff --git a/README.md b/README.md
index 376c92296f..3ffce7c8c3 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/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
* [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-children-prop](docs/rules/no-children-prop.md): Prevent passing children as props
* [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
@@ -166,6 +167,7 @@ The rules enabled in this configuration are:
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md)
* [react/jsx-uses-react](docs/rules/jsx-uses-react.md)
* [react/jsx-uses-vars](docs/rules/jsx-uses-vars.md)
+* [react/no-danger](docs/rules/no-danger.md)
* [react/no-deprecated](docs/rules/no-deprecated.md)
* [react/no-direct-mutation-state](docs/rules/no-direct-mutation-state.md)
* [react/no-find-dom-node](docs/rules/no-find-dom-node.md)
diff --git a/docs/rules/no-children-prop.md b/docs/rules/no-children-prop.md
new file mode 100644
index 0000000000..e49c7d8715
--- /dev/null
+++ b/docs/rules/no-children-prop.md
@@ -0,0 +1,36 @@
+# Prevent passing of children as props (no-children-prop)
+
+Children should always be actual children, not passed in as a prop.
+
+When using JSX, the children should be nested between the opening and closing
+tags. When not using JSX, the children should be passed as additional
+arguments to `React.createElement`.
+
+## Rule Details
+
+The following patterns are considered warnings:
+
+```jsx
+
+
+} />
+
+
+React.createElement("div", { children: 'Children' })
+```
+
+The following patterns are not considered warnings:
+
+```jsx
+Children
+
+Children
+
+
+ Child 1
+ Child 2
+
+
+React.createElement("div", {}, 'Children')
+React.createElement("div", 'Child 1', 'Child 2')
+```
diff --git a/index.js b/index.js
index ff5d9d9eef..6bc2671339 100644
--- a/index.js
+++ b/index.js
@@ -57,7 +57,8 @@ var rules = {
'no-find-dom-node': require('./lib/rules/no-find-dom-node'),
'no-danger-with-children': require('./lib/rules/no-danger-with-children'),
'style-prop-object': require('./lib/rules/style-prop-object'),
- 'no-unused-prop-types': require('./lib/rules/no-unused-prop-types')
+ 'no-unused-prop-types': require('./lib/rules/no-unused-prop-types'),
+ 'no-children-prop': require('./lib/rules/no-children-prop')
};
var ruleNames = Object.keys(rules);
diff --git a/lib/rules/no-children-prop.js b/lib/rules/no-children-prop.js
new file mode 100644
index 0000000000..31d1b965b5
--- /dev/null
+++ b/lib/rules/no-children-prop.js
@@ -0,0 +1,69 @@
+/**
+ * @fileoverview Prevent passing of children as props
+ * @author Benjamin Stepp
+ */
+'use strict';
+
+// ------------------------------------------------------------------------------
+// Helpers
+// ------------------------------------------------------------------------------
+
+/**
+ * Checks if the node is a createElement call with a props literal.
+ * @param {ASTNode} node - The AST node being checked.
+ * @returns {Boolean} - True if node is a createElement call with a props
+ * object literal, False if not.
+*/
+function isCreateElementWithProps(node) {
+ return node.callee
+ && node.callee.type === 'MemberExpression'
+ && node.callee.property.name === 'createElement'
+ && node.arguments.length > 1
+ && node.arguments[1].type === 'ObjectExpression';
+}
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = {
+ meta: {
+ docs: {
+ description: 'Prevent passing of children as props.',
+ category: 'Best Practices',
+ recommended: false
+ },
+ schema: []
+ },
+ create: function(context) {
+ return {
+ JSXAttribute: function(node) {
+ if (node.name.name !== 'children') {
+ return;
+ }
+
+ context.report({
+ node: node,
+ message: 'Do not pass children as props. Instead, nest children between the opening and closing tags.'
+ });
+ },
+ CallExpression: function(node) {
+ if (!isCreateElementWithProps(node)) {
+ return;
+ }
+
+ var props = node.arguments[1].properties;
+ var childrenProp = props.find(function(prop) {
+ return prop.key.name === 'children';
+ });
+
+ if (childrenProp) {
+ context.report({
+ node: node,
+ message: 'Do not pass children as props. Instead, pass them as additional arguments to React.createElement.'
+ });
+ }
+ }
+ };
+ }
+};
diff --git a/tests/lib/rules/no-children-prop.js b/tests/lib/rules/no-children-prop.js
new file mode 100644
index 0000000000..d0073dc0f2
--- /dev/null
+++ b/tests/lib/rules/no-children-prop.js
@@ -0,0 +1,237 @@
+/**
+ * @fileoverview Tests for no-children-prop
+ * @author Benjamin Stepp
+ */
+
+'use strict';
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+var rule = require('../../../lib/rules/no-children-prop');
+var RuleTester = require('eslint').RuleTester;
+
+var parserOptions = {
+ ecmaVersion: 6,
+ ecmaFeatures: {
+ jsx: true
+ }
+};
+
+var JSX_ERROR = 'Do not pass children as props. Instead, nest children between \
+the opening and closing tags.';
+var CREATE_ELEMENT_ERROR = 'Do not pass children as props. Instead, pass them \
+as additional arguments to React.createElement.';
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+var ruleTester = new RuleTester();
+ruleTester.run('no-children-prop', rule, {
+ valid: [
+ {
+ code: ';',
+ parserOptions: parserOptions
+ },
+ {
+ code: ';',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {});',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined);',
+ parserOptions: parserOptions
+ },
+ {
+ code: ';',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {className: "class-name"});',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'Children
;',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {}, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'Children
;',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {className: "class-name"}, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: ';',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", React.createElement("div"));',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {}, React.createElement("div"));',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined, React.createElement("div"));',
+ parserOptions: parserOptions
+ },
+ {
+ code: ';',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", React.createElement("div"), React.createElement("div"));',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {}, React.createElement("div"), React.createElement("div"));',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined, React.createElement("div"), React.createElement("div"));',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", [React.createElement("div"), React.createElement("div")]);',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {}, [React.createElement("div"), React.createElement("div")]);',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined, [React.createElement("div"), React.createElement("div")]);',
+ parserOptions: parserOptions
+ },
+ {
+ code: '',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent);',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, {});',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, undefined);',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'Children;',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, {}, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, undefined, "Children");',
+ parserOptions: parserOptions
+ },
+ {
+ code: ';',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, {className: "class-name"});',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'Children;',
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, {className: "class-name"}, "Children");',
+ parserOptions: parserOptions
+ }
+ ],
+ invalid: [
+ {
+ code: ';',
+ errors: [{message: JSX_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: '} />;',
+ errors: [{message: JSX_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: ', ]} />;',
+ errors: [{message: JSX_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'Children
;',
+ errors: [{message: JSX_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {children: "Children"});',
+ errors: [{message: CREATE_ELEMENT_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {children: "Children"}, "Children");',
+ errors: [{message: CREATE_ELEMENT_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {children: React.createElement("div")});',
+ errors: [{message: CREATE_ELEMENT_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement("div", {children: [React.createElement("div"), React.createElement("div")]});',
+ errors: [{message: CREATE_ELEMENT_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: '',
+ errors: [{message: JSX_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, {children: "Children"});',
+ errors: [{message: CREATE_ELEMENT_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: ';',
+ errors: [{message: JSX_ERROR}],
+ parserOptions: parserOptions
+ },
+ {
+ code: 'React.createElement(MyComponent, {children: "Children", className: "class-name"});',
+ errors: [{message: CREATE_ELEMENT_ERROR}],
+ parserOptions: parserOptions
+ }
+ ]
+});