diff --git a/packages/eslint-plugin/src/rules/__tests__/prefer-ideal-image.test.ts b/packages/eslint-plugin/src/rules/__tests__/prefer-ideal-image.test.ts
new file mode 100644
index 000000000000..6949f92cb86d
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/__tests__/prefer-ideal-image.test.ts
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import rule from '../prefer-ideal-image';
+import {RuleTester} from './testUtils';
+
+const errorMsg = [{messageId: 'idealImageError'}] as const;
+const errorWarning = [{messageId: 'idealImageWarning'}] as const;
+
+const ruleTester = new RuleTester({
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+});
+
+ruleTester.run('prefer-ideal-image', rule, {
+ valid: [
+ {
+ code: "",
+ },
+ {
+ code: "",
+ },
+ {
+ code: "
",
+ },
+ {
+ code: '
',
+ },
+ {
+ code: '
',
+ },
+ {
+ code: '
',
+ },
+ {
+ code: "
",
+ },
+ ],
+ invalid: [
+ {
+ code: "
",
+ errors: errorMsg,
+ },
+ {
+ code: "
",
+ errors: errorWarning,
+ },
+ {
+ code: "
",
+ errors: errorWarning,
+ },
+ {
+ code: "
",
+ errors: errorWarning,
+ },
+ ],
+});
diff --git a/packages/eslint-plugin/src/rules/prefer-ideal-image.ts b/packages/eslint-plugin/src/rules/prefer-ideal-image.ts
new file mode 100644
index 000000000000..f727261683a1
--- /dev/null
+++ b/packages/eslint-plugin/src/rules/prefer-ideal-image.ts
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import {createRule} from '../util';
+import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
+
+type Options = [];
+type MessageIds = 'idealImageError' | 'idealImageWarning';
+
+const docsUrl =
+ 'https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-ideal-image';
+
+export default createRule({
+ name: 'prefer-ideal-image',
+ meta: {
+ type: 'problem',
+ docs: {
+ description:
+ 'enforce using Docusaurus IdealImage plugin component instead of
tags',
+ recommended: false,
+ },
+ schema: [],
+ messages: {
+ idealImageError: `Do not use an \`
\` element to embed images. Use the \`\` component from \`@theme/IdealImage\` instead. See ${docsUrl}`,
+ idealImageWarning: `If this is a local file do not use an \`
\` element to embed images. Use the \`\` component from \`@theme/IdealImage\` instead. See ${docsUrl}`,
+ },
+ },
+ defaultOptions: [],
+
+ create(context) {
+ return {
+ JSXOpeningElement(node) {
+ const elementName = (node.name as TSESTree.JSXIdentifier).name;
+
+ if (elementName !== 'img') {
+ return;
+ }
+
+ const srcAttr = node.attributes.find(
+ (attr): attr is TSESTree.JSXAttribute =>
+ attr.type === 'JSXAttribute' && attr.name.name === 'src',
+ );
+
+ const value = srcAttr?.value;
+
+ if (!value) {
+ return;
+ }
+
+ if (value.type === 'Literal' && typeof value.value === 'string') {
+ const val = value.value;
+
+ if (val.toLowerCase().endsWith('.svg')) {
+ return;
+ }
+
+ if (val.startsWith('http') || val.startsWith('//')) {
+ return;
+ }
+ if (
+ val.startsWith('./') ||
+ val.startsWith('../') ||
+ val.startsWith('/')
+ ) {
+ context.report({node: value, messageId: 'idealImageWarning'});
+ }
+ return;
+ }
+
+ if (value.type === 'JSXExpressionContainer') {
+ const expr = value.expression;
+
+ if (expr.type === 'TemplateLiteral') {
+ const firstPart = expr.quasis[0]?.value.raw;
+ if (firstPart?.startsWith('http') || firstPart?.startsWith('//')) {
+ return;
+ }
+ }
+
+ if (
+ expr.type === 'CallExpression' &&
+ expr.callee.type === 'Identifier' &&
+ expr.callee.name === 'require'
+ ) {
+ context.report({node, messageId: 'idealImageError'});
+ }
+ }
+ },
+ };
+ },
+});
diff --git a/website/docs/api/misc/eslint-plugin/README.mdx b/website/docs/api/misc/eslint-plugin/README.mdx
index a0d41ee4d458..bdf355ec555c 100644
--- a/website/docs/api/misc/eslint-plugin/README.mdx
+++ b/website/docs/api/misc/eslint-plugin/README.mdx
@@ -54,6 +54,7 @@ For more fine-grained control, you can also enable the plugin manually and confi
| [`@docusaurus/string-literal-i18n-messages`](./string-literal-i18n-messages.mdx) | Enforce translate APIs to be called on plain text labels | ✅ |
| [`@docusaurus/no-html-links`](./no-html-links.mdx) | Ensures @docusaurus/Link is used instead of `` tags | ✅ |
| [`@docusaurus/prefer-docusaurus-heading`](./prefer-docusaurus-heading.mdx) | Ensures @theme/Heading is used instead of `` tags for headings | ✅ |
+| [`@docusaurus/prefer-ideal-image`](./prefer-ideal-image.mdx) | Ensures @theme/IdealImage is used instead of `
` tags for embedding images | |
✅ = recommended
diff --git a/website/docs/api/misc/eslint-plugin/prefer-ideal-image.mdx b/website/docs/api/misc/eslint-plugin/prefer-ideal-image.mdx
new file mode 100644
index 000000000000..f2d306879b28
--- /dev/null
+++ b/website/docs/api/misc/eslint-plugin/prefer-ideal-image.mdx
@@ -0,0 +1,50 @@
+---
+slug: /api/misc/@docusaurus/eslint-plugin/prefer-ideal-image
+---
+
+# prefer-ideal-image
+
+Ensure that the `` component provided by the [`@docusaurus/plugin-ideal-image`](../../plugins/plugin-ideal-image.mdx) plugin is used instead of standard `
` tags for local assets.
+
+The `@theme/IdealImage` component automatically generates responsive images, provides lazy-loading, and adds low-quality image placeholders (LQIP) to improve LCP and user experience.
+
+## Rule Details {#details}
+
+This rule flags standard HTML `
` tags that point to local files, suggesting the use of `IdealImage` for better optimization.
+
+Examples of **incorrect** code for this rule:
+
+```jsx
+// Error: Definitely a local image via require()
+
+
+// Warning: Likely a local image via relative path
+
+
+// Warning: Root-relative path usually points to the static folder
+
+```
+
+Examples of **correct** code for this rule:
+
+```jsx
+// Optimized using the IdealImage component
+import IdealImage from '@theme/IdealImage';
+
+
+
+// External images are ignored
+
+
+// SVGs are ignored as IdealImage does not support them
+
+```
+
+## When to not use it
+
+If you have not installed or do not plan to use @docusaurus/plugin-ideal-image, you should keep this rule disabled.
+
+## Further Reading {#further-reading}
+
+- https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-ideal-image
+- https://web.dev/articles/browser-level-image-lazy-loading