diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99a23280e5..b67ee92808 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2808,3 +2808,4 @@ If you're still not using React 15 you can keep the old behavior by setting the
[`jsx-curly-newline`]: docs/rules/jsx-curly-newline.md
[`jsx-no-useless-fragment`]: docs/rules/jsx-no-useless-fragment.md
[`jsx-no-script-url`]: docs/rules/jsx-no-script-url.md
+[`no-adjacent-inline-elements`]: docs/rules/no-adjacent-inline-elements.md
diff --git a/docs/rules/no-adjacent-inline-elements.md b/docs/rules/no-adjacent-inline-elements.md
new file mode 100644
index 0000000000..db7d9b41ec
--- /dev/null
+++ b/docs/rules/no-adjacent-inline-elements.md
@@ -0,0 +1,24 @@
+# Prevent adjacent inline elements not separated by whitespace. (no-adjacent-inline-elements)
+
+Adjacent inline elements not separated by whitespace will bump up against each
+other when viewed in an unstyled manner, which usually isn't desirable.
+
+## Rule Details
+
+The following patterns are considered warnings:
+
+```jsx
+
+
+
+React.createElement("div", undefined, [React.createElement("a"), React.createElement("span")]);
+```
+
+The following patterns are not considered warnings:
+
+```jsx
+
+
+
+React.createElement("div", undefined, [React.createElement("a"), " ", React.createElement("a")]);
+```
diff --git a/index.js b/index.js
index 6db76d0aee..2396353682 100644
--- a/index.js
+++ b/index.js
@@ -52,6 +52,7 @@ const allRules = {
'jsx-uses-vars': require('./lib/rules/jsx-uses-vars'),
'jsx-wrap-multilines': require('./lib/rules/jsx-wrap-multilines'),
'no-access-state-in-setstate': require('./lib/rules/no-access-state-in-setstate'),
+ 'no-adjacent-inline-elements': require('./lib/rules/no-adjacent-inline-elements'),
'no-array-index-key': require('./lib/rules/no-array-index-key'),
'no-children-prop': require('./lib/rules/no-children-prop'),
'no-danger': require('./lib/rules/no-danger'),
diff --git a/lib/rules/no-adjacent-inline-elements.js b/lib/rules/no-adjacent-inline-elements.js
new file mode 100644
index 0000000000..60104542b4
--- /dev/null
+++ b/lib/rules/no-adjacent-inline-elements.js
@@ -0,0 +1,115 @@
+/**
+ * @fileoverview Prevent adjacent inline elements not separated by whitespace.
+ * @author Sean Hayes
+ */
+
+'use strict';
+
+// ------------------------------------------------------------------------------
+// Helpers
+// ------------------------------------------------------------------------------
+
+// https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
+const inlineNames = [
+ 'a',
+ 'b',
+ 'big',
+ 'i',
+ 'small',
+ 'tt',
+ 'abbr',
+ 'acronym',
+ 'cite',
+ 'code',
+ 'dfn',
+ 'em',
+ 'kbd',
+ 'strong',
+ 'samp',
+ 'time',
+ 'var',
+ 'bdo',
+ 'br',
+ 'img',
+ 'map',
+ 'object',
+ 'q',
+ 'script',
+ 'span',
+ 'sub',
+ 'sup',
+ 'button',
+ 'input',
+ 'label',
+ 'select',
+ 'textarea'
+];
+// Note: raw will be transformed into \u00a0.
+const whitespaceRegex = /(?:^\s|\s$)/;
+
+function isInline(node) {
+ if (node.type === 'Literal') {
+ // Regular whitespace will be removed.
+ const value = node.value;
+ // To properly separate inline elements, each end of the literal will need
+ // whitespace.
+ return !whitespaceRegex.test(value);
+ }
+ if (node.type === 'JSXElement' && inlineNames.indexOf(node.openingElement.name.name) > -1) {
+ return true;
+ }
+ if (node.type === 'CallExpression' && inlineNames.indexOf(node.arguments[0].value) > -1) {
+ return true;
+ }
+ return false;
+}
+
+const ERROR = 'Child elements which render as inline HTML elements should be separated by a space or wrapped in block level elements.';
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = {
+ ERROR,
+ meta: {
+ docs: {
+ description: 'Prevent adjacent inline elements not separated by whitespace.',
+ category: 'Best Practices',
+ recommended: false
+ },
+ schema: []
+ },
+ create(context) {
+ function validate(node, children) {
+ let currentIsInline = false;
+ let previousIsInline = false;
+ for (let i = 0; i < children.length; i++) {
+ currentIsInline = isInline(children[i]);
+ if (previousIsInline && currentIsInline) {
+ context.report({
+ node,
+ message: ERROR
+ });
+ return;
+ }
+ previousIsInline = currentIsInline;
+ }
+ }
+ return {
+ JSXElement(node) {
+ validate(node, node.children);
+ },
+ CallExpression(node) {
+ if (!node.callee || node.callee.type !== 'MemberExpression' || node.callee.property.name !== 'createElement') {
+ return;
+ }
+ if (node.arguments.length < 2) {
+ return;
+ }
+ const children = node.arguments[2].elements;
+ validate(node, children);
+ }
+ };
+ }
+};
diff --git a/tests/lib/rules/no-adjacent-inline-elements.js b/tests/lib/rules/no-adjacent-inline-elements.js
new file mode 100644
index 0000000000..c196a0ee20
--- /dev/null
+++ b/tests/lib/rules/no-adjacent-inline-elements.js
@@ -0,0 +1,102 @@
+/**
+ * @fileoverview Tests for no-adjacent-inline-elements
+ * @author Sean Hayes
+ */
+
+'use strict';
+
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+const RuleTester = require('eslint').RuleTester;
+const rule = require('../../../lib/rules/no-adjacent-inline-elements');
+
+const ERROR = rule.ERROR;
+
+const parserOptions = {
+ ecmaVersion: 6,
+ ecmaFeatures: {
+ experimentalObjectRestSpread: true,
+ jsx: true
+ }
+};
+
+// -----------------------------------------------------------------------------
+// Tests
+// -----------------------------------------------------------------------------
+
+const ruleTester = new RuleTester();
+ruleTester.run('no-adjacent-inline-elements', rule, {
+ valid: [
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ parserOptions
+ },
+ {
+ code: ';',
+ errors: [{message: ERROR}],
+ parserOptions
+ },
+ {
+ code: ('React.createElement("div", undefined, [React.createElement("a"), ' +
+ '" some text ", React.createElement("a")]);'),
+ errors: [{message: ERROR}],
+ parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined, [React.createElement("a"), " ", React.createElement("a")]);',
+ errors: [{message: ERROR}],
+ parserOptions
+ }
+ ],
+ invalid: [
+ {
+ code: ';',
+ errors: [{message: ERROR}],
+ parserOptions
+ },
+ {
+ code: ';',
+ errors: [{message: ERROR}],
+ parserOptions
+ },
+ {
+ code: 'React.createElement("div", undefined, [React.createElement("a"), React.createElement("span")]);',
+ errors: [{message: ERROR}],
+ parserOptions
+ }
+ ]
+});