diff --git a/.eslintplugin.js b/.eslintplugin.js
index 50632e51018..348def29c45 100644
--- a/.eslintplugin.js
+++ b/.eslintplugin.js
@@ -4,4 +4,5 @@ exports.rules = {
'require-license-header': require('./scripts/eslint-plugin/require_license_header'),
'forward-ref': require('./scripts/eslint-plugin/forward_ref_display_name'),
'css-logical-properties': require('./scripts/eslint-plugin/css_logical_properties'),
+ 'css_before_spread_props': require('./scripts/eslint-plugin/css_before_spread_props'),
};
diff --git a/.eslintrc.js b/.eslintrc.js
index f3e0830b119..a366039b97e 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -45,6 +45,7 @@ module.exports = {
'local/href-with-rel': 'error',
'local/forward-ref': 'error',
'local/css-logical-properties': 'error',
+ 'local/css_before_spread_props': 'error',
'local/require-license-header': [
'warn',
{
diff --git a/scripts/eslint-plugin/css_before_spread_props.js b/scripts/eslint-plugin/css_before_spread_props.js
new file mode 100644
index 00000000000..033695510a5
--- /dev/null
+++ b/scripts/eslint-plugin/css_before_spread_props.js
@@ -0,0 +1,48 @@
+module.exports = {
+ meta: {
+ type: 'problem',
+ docs: {
+ description: 'Enforce CSS props are declared before spread props',
+ },
+ },
+ create: function (context) {
+ const allElementsArr = [];
+
+ return {
+ JSXElement(node) {
+ const attributesArr = [];
+ node.openingElement.attributes.forEach((attribute) =>
+ attributesArr.push(attribute)
+ );
+ allElementsArr.push(attributesArr);
+ },
+ 'Program:exit'() {
+ allElementsArr.forEach((elementArr) => {
+ const cssPropsIndex = elementArr.findIndex(
+ (node) => node.name && node.name.name === 'css'
+ );
+ if (cssPropsIndex === -1) return;
+
+ const spreadPropsIndex = elementArr.findIndex(
+ (node) => node.type === 'JSXSpreadAttribute'
+ );
+ if (spreadPropsIndex === -1) return;
+
+ if (cssPropsIndex > spreadPropsIndex) {
+ context.report({
+ loc: {
+ line: elementArr[cssPropsIndex].loc.start.line,
+ column: elementArr[cssPropsIndex].loc.start.column,
+ },
+ message:
+ '{{ identifier }}: CSS props must be declared before spread props.',
+ data: {
+ identifier: elementArr[spreadPropsIndex].argument.name,
+ },
+ });
+ }
+ });
+ },
+ };
+ },
+};
diff --git a/scripts/eslint-plugin/css_before_spread_props.test.js b/scripts/eslint-plugin/css_before_spread_props.test.js
new file mode 100644
index 00000000000..1df9860ebce
--- /dev/null
+++ b/scripts/eslint-plugin/css_before_spread_props.test.js
@@ -0,0 +1,245 @@
+import rule from './css_before_spread_props.js';
+const RuleTester = require('eslint').RuleTester;
+
+const ruleTester = new RuleTester({
+ parser: require.resolve('babel-eslint'),
+});
+
+const valid = [
+ {
+ code: `
+ {buttonIcon}
+
+ `,
+ },
+ {
+ code: `
+ {buttonIcon}
+
+ `,
+ },
+ {
+ code: `
+ {buttonIcon}
+
+ `,
+ },
+ {
+ code: `
+ `,
+ },
+ {
+ code: `
+ `,
+ },
+ {
+ code: `
+ `,
+ },
+ {
+ code: `