diff --git a/docs/rules/no-sx-prop.md b/docs/rules/no-sx-prop.md
new file mode 100644
index 0000000..e3128cf
--- /dev/null
+++ b/docs/rules/no-sx-prop.md
@@ -0,0 +1,33 @@
+# No Wildcard Imports
+
+## Rule Details
+
+This rule enforces that no sx props are used with `@primer/react`.
+
+👎 Examples of **incorrect** code for this rule
+
+```jsx
+import {Button} from '@primer/react'
+
+function ExampleComponent() {
+ return (
+
+ )
+}
+```
+
+👍 Examples of **correct** code for this rule:
+
+```jsx
+import {Button} from '@primer/react'
+
+function ExampleComponent() {
+ return
+}
+```
diff --git a/src/index.js b/src/index.js
index bc284b0..fe010f2 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,6 +12,7 @@ module.exports = {
'a11y-use-next-tooltip': require('./rules/a11y-use-next-tooltip'),
'use-deprecated-from-deprecated': require('./rules/use-deprecated-from-deprecated'),
'no-wildcard-imports': require('./rules/no-wildcard-imports'),
+ 'no-sx-prop': require('./rules/no-sx-prop'),
'no-unnecessary-components': require('./rules/no-unnecessary-components'),
'prefer-action-list-item-onselect': require('./rules/prefer-action-list-item-onselect'),
},
diff --git a/src/rules/__tests__/no-sx-prop.test.js b/src/rules/__tests__/no-sx-prop.test.js
new file mode 100644
index 0000000..33b772b
--- /dev/null
+++ b/src/rules/__tests__/no-sx-prop.test.js
@@ -0,0 +1,34 @@
+'use strict'
+
+const {RuleTester} = require('eslint')
+const rule = require('../no-sx-prop')
+
+const ruleTester = new RuleTester({
+ parser: require.resolve('@typescript-eslint/parser'),
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+})
+
+ruleTester.run('no-sx-prop', rule, {
+ valid: [],
+ invalid: [
+ {
+ code: `
+ import {SegmentedControl} from '@primer/react';
+ function Example() {
+ return
+ }
+ `,
+ errors: [
+ {
+ messageId: 'sxProp',
+ },
+ ],
+ },
+ ],
+})
diff --git a/src/rules/no-sx-prop.js b/src/rules/no-sx-prop.js
new file mode 100644
index 0000000..28a8d2f
--- /dev/null
+++ b/src/rules/no-sx-prop.js
@@ -0,0 +1,89 @@
+'use strict'
+
+const url = require('../url')
+
+const forbidden = new Set([
+ // 'ActionList',
+ // 'ActionList.Divider',
+ // 'ActionList.Group',
+ // 'ActionList.Item',
+ // 'ActionList.LeadingVisual',
+ // 'ActionList.LinkItem',
+
+ // 'ActionMenu.Button',
+ // 'ActionMenu.Overlay',
+
+ // 'Avatar',
+ // 'AvatarStack',
+
+ // 'BorderBox',
+ // 'Box',
+
+ // 'BranchName',
+
+ // 'Breadcrumbs',
+ // 'Breadcrumbs.Item',
+
+ 'SegmentedControl',
+ 'SegmentedControl.Button',
+
+ 'SplitPageLayout.Pane',
+
+ // 'UnderlineNav',
+ // 'UnderlineNav.Item',
+])
+
+/**
+ * @type {import('eslint').Rule.RuleModule}
+ */
+module.exports = {
+ meta: {
+ type: 'problem',
+ docs: {
+ description: 'The sx prop is discouraged. Use CSS Modules instead',
+ recommended: true,
+ url: url(module),
+ },
+ fixable: true,
+ schema: [],
+ messages: {
+ sxProp:
+ 'The `sx` prop has been deprecated by @primer/react and will be removed in the next major release. Please migrate to CSS Modules instead.',
+ },
+ },
+ create(context) {
+ return {
+ JSXOpeningElement(node) {
+ let name = null
+
+ if (
+ node.name.type === 'JSXMemberExpression' &&
+ node.name.object.type === 'JSXIdentifier' &&
+ node.name.property.type === 'JSXIdentifier'
+ ) {
+ name = `${node.name.object.name}.${node.name.property.name}`
+ } else if (node.name.type === 'JSXIdentifier') {
+ name = node.name.name
+ }
+
+ if (!forbidden.has(name)) {
+ return
+ }
+
+ const hasSxProp = node.attributes.some(attr => {
+ if (attr.name?.type === 'JSXIdentifier' && attr.name.name === 'sx') {
+ return true
+ }
+ return false
+ })
+
+ if (hasSxProp) {
+ context.report({
+ node,
+ messageId: 'sxProp',
+ })
+ }
+ },
+ }
+ },
+}