diff --git a/.changeset/wicked-areas-jog.md b/.changeset/wicked-areas-jog.md
new file mode 100644
index 00000000..5582f9e1
--- /dev/null
+++ b/.changeset/wicked-areas-jog.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-primer-react': minor
+---
+
+Add `no-deprecated-experimental-components` rule
diff --git a/README.md b/README.md
index 03a4c86b..e0bf39c5 100644
--- a/README.md
+++ b/README.md
@@ -40,3 +40,4 @@ ESLint rules for Primer React
- [a11y-link-in-text-block](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/a11y-link-in-text-block.md)
- [a11y-remove-disable-tooltip](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/a11y-remove-disable-tooltip.md)
- [a11y-use-accessible-tooltip](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/a11y-use-accessible-tooltip.md)
+- [no-deprecated-experimental-components](https://github.com/primer/eslint-plugin-primer-react/blob/main/docs/rules/no-deprecated-experimental-components.md)
diff --git a/docs/rules/no-deprecated-experimental-components.md b/docs/rules/no-deprecated-experimental-components.md
new file mode 100644
index 00000000..f57130de
--- /dev/null
+++ b/docs/rules/no-deprecated-experimental-components.md
@@ -0,0 +1,29 @@
+# No deprecated experimental components
+
+## Rule Details
+
+This rule discourages the usage of specific imports from `@primer/react/experimental`.
+
+👎 Examples of **incorrect** code for this rule
+
+```jsx
+import {SelectPanel} from '@primer/react/experimental'
+
+function ExampleComponent() {
+ return
+}
+```
+
+👍 Examples of **correct** code for this rule:
+
+You can satisfy the rule by either converting to the non-experimental version:
+
+```jsx
+import {SelectPanel} from '@primer/react'
+
+function ExampleComponent() {
+ return
+}
+```
+
+Or by removing usage of the component.
diff --git a/src/configs/recommended.js b/src/configs/recommended.js
index e29c3c00..1d4a9f33 100644
--- a/src/configs/recommended.js
+++ b/src/configs/recommended.js
@@ -12,6 +12,7 @@ module.exports = {
rules: {
'primer-react/direct-slot-children': 'error',
'primer-react/no-system-props': 'warn',
+ 'primer-react/no-deprecated-experimental-components': 'warn',
'primer-react/a11y-tooltip-interactive-trigger': 'error',
'primer-react/new-color-css-vars': 'error',
'primer-react/a11y-explicit-heading': 'error',
diff --git a/src/index.js b/src/index.js
index 9ba22767..1cb3a431 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,6 +3,7 @@ module.exports = {
'direct-slot-children': require('./rules/direct-slot-children'),
'no-deprecated-entrypoints': require('./rules/no-deprecated-entrypoints'),
'no-system-props': require('./rules/no-system-props'),
+ 'no-deprecated-experimental-components': require('./rules/no-deprecated-experimental-components'),
'a11y-tooltip-interactive-trigger': require('./rules/a11y-tooltip-interactive-trigger'),
'new-color-css-vars': require('./rules/new-color-css-vars'),
'a11y-explicit-heading': require('./rules/a11y-explicit-heading'),
diff --git a/src/rules/__tests__/no-deprecated-experimental-components.test.js b/src/rules/__tests__/no-deprecated-experimental-components.test.js
new file mode 100644
index 00000000..3488328a
--- /dev/null
+++ b/src/rules/__tests__/no-deprecated-experimental-components.test.js
@@ -0,0 +1,44 @@
+'use strict'
+
+const {RuleTester} = require('eslint')
+const rule = require('../no-deprecated-experimental-components')
+
+const ruleTester = new RuleTester({
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+})
+
+ruleTester.run('no-deprecated-experimental-components', rule, {
+ valid: [
+ {
+ code: `import {SelectPanel} from '@primer/react'`,
+ },
+ {
+ code: `import {DataTable} from '@primer/react/experimental'`,
+ },
+ {
+ code: `import {DataTable, ActionBar} from '@primer/react/experimental'`,
+ },
+ ],
+ invalid: [
+ // Single experimental import
+ {
+ code: `import {SelectPanel} from '@primer/react/experimental'`,
+ errors: [
+ 'SelectPanel is deprecated. Please import from the stable entrypoint (@primer/react) if available, or check https://primer.style/product/components/ for alternative components.',
+ ],
+ },
+ // Multiple experimental import
+ {
+ code: `import {SelectPanel, DataTable, ActionBar} from '@primer/react/experimental'`,
+ errors: [
+ 'SelectPanel is deprecated. Please import from the stable entrypoint (@primer/react) if available, or check https://primer.style/product/components/ for alternative components.',
+ ],
+ },
+ ],
+})
diff --git a/src/rules/no-deprecated-experimental-components.js b/src/rules/no-deprecated-experimental-components.js
new file mode 100644
index 00000000..3746c9fa
--- /dev/null
+++ b/src/rules/no-deprecated-experimental-components.js
@@ -0,0 +1,67 @@
+'use strict'
+
+const url = require('../url')
+
+const components = [
+ {
+ identifier: 'SelectPanel',
+ entrypoint: '@primer/react/experimental',
+ },
+]
+
+const entrypoints = new Map()
+
+for (const component of components) {
+ if (!entrypoints.has(component.entrypoint)) {
+ entrypoints.set(component.entrypoint, new Set())
+ }
+ entrypoints.get(component.entrypoint).add(component.identifier)
+}
+
+/**
+ * @type {import('eslint').Rule.RuleModule}
+ */
+module.exports = {
+ meta: {
+ type: 'problem',
+ docs: {
+ description: 'Use a stable component from the `@primer/react` entrypoint, or check the docs for alternatives',
+ recommended: true,
+ url: url(module),
+ },
+ fixable: true,
+ schema: [],
+ },
+ create(context) {
+ return {
+ ImportDeclaration(node) {
+ if (!entrypoints.has(node.source.value)) {
+ return
+ }
+
+ const entrypoint = entrypoints.get(node.source.value)
+
+ const experimental = node.specifiers.filter(specifier => {
+ return entrypoint.has(specifier.imported.name)
+ })
+
+ const components = experimental.map(specifier => specifier.imported.name)
+
+ if (experimental.length === 0) {
+ return
+ }
+
+ if (experimental.length > 0) {
+ const message = `${components.join(', ')} ${
+ components.length > 1 ? 'are' : 'is'
+ } deprecated. Please import from the stable entrypoint (@primer/react) if available, or check https://primer.style/product/components/ for alternative components.`
+
+ context.report({
+ node,
+ message,
+ })
+ }
+ },
+ }
+ },
+}