diff --git a/packages/e2e-tests/plugins/plugins-api.php b/packages/e2e-tests/plugins/plugins-api.php
index fb8054924cebb..10e35f16226f2 100644
--- a/packages/e2e-tests/plugins/plugins-api.php
+++ b/packages/e2e-tests/plugins/plugins-api.php
@@ -86,6 +86,19 @@ function enqueue_plugins_api_plugin_scripts() {
filemtime( plugin_dir_path( __FILE__ ) . 'plugins-api/document-setting.js' ),
true
);
+
+ wp_enqueue_script(
+ 'gutenberg-test-plugins-api-preview-menu',
+ plugins_url( 'plugins-api/preview-menu.js', __FILE__ ),
+ array(
+ 'wp-editor',
+ 'wp-element',
+ 'wp-i18n',
+ 'wp-plugins',
+ ),
+ filemtime( plugin_dir_path( __FILE__ ) . 'plugins-api/preview-menu.js' ),
+ true
+ );
}
add_action( 'init', 'enqueue_plugins_api_plugin_scripts' );
diff --git a/packages/e2e-tests/plugins/plugins-api/preview-menu.js b/packages/e2e-tests/plugins/plugins-api/preview-menu.js
new file mode 100644
index 0000000000000..1aa53b2e8509a
--- /dev/null
+++ b/packages/e2e-tests/plugins/plugins-api/preview-menu.js
@@ -0,0 +1,14 @@
+( function () {
+ const { __ } = wp.i18n;
+ const { registerPlugin } = wp.plugins;
+ const PluginPreviewMenuItem = wp.editor.PluginPreviewMenuItem;
+ const el = wp.element.createElement;
+
+ function CustomPreviewMenuItem() {
+ return el( PluginPreviewMenuItem, {}, __( 'Custom Preview' ) );
+ }
+
+ registerPlugin( 'custom-preview-menu-item', {
+ render: CustomPreviewMenuItem,
+ } );
+} )();
diff --git a/packages/editor/README.md b/packages/editor/README.md
index 89ea15ef37849..ebd4af31e287d 100644
--- a/packages/editor/README.md
+++ b/packages/editor/README.md
@@ -862,6 +862,43 @@ _Returns_
- `Component`: The component to be rendered.
+### PluginPreviewMenuItem
+
+Renders a menu item in the Preview dropdown, which can be used as a button or link depending on the props provided. The text within the component appears as the menu item label.
+
+_Usage_
+
+```jsx
+import { __ } from '@wordpress/i18n';
+import { PluginPreviewMenuItem } from '@wordpress/editor';
+import { external } from '@wordpress/icons';
+
+function onPreviewClick() {
+ // Handle preview action
+}
+
+const ExternalPreviewMenuItem = () => (
+
+ { __( 'Preview in new tab' ) }
+
+);
+registerPlugin( 'external-preview-menu-item', {
+ render: ExternalPreviewMenuItem,
+} );
+```
+
+_Parameters_
+
+- _props_ `Object`: Component properties.
+- _props.href_ `[string]`: When `href` is provided, the menu item is rendered as an anchor instead of a button. It corresponds to the `href` attribute of the anchor.
+- _props.icon_ `[WPBlockTypeIconRender]`: The icon to be rendered to the left of the menu item label. Can be a Dashicon slug or an SVG WP element.
+- _props.onClick_ `[Function]`: The callback function to be executed when the user clicks the menu item.
+- _props.other_ `[...*]`: Any additional props are passed through to the underlying MenuItem component.
+
+_Returns_
+
+- `Component`: The rendered menu item component.
+
### PluginSidebar
Renders a sidebar when activated. The contents within the `PluginSidebar` will appear as content within the sidebar. It also automatically renders a corresponding `PluginSidebarMenuItem` component when `isPinnable` flag is set to `true`. If you wish to display the sidebar, you can with use the `PluginSidebarMoreMenuItem` component or the `wp.data.dispatch` API:
diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js
index 91dcc883d661b..b42566aac653b 100644
--- a/packages/editor/src/components/index.js
+++ b/packages/editor/src/components/index.js
@@ -32,6 +32,7 @@ export { default as PluginMoreMenuItem } from './plugin-more-menu-item';
export { default as PluginPostPublishPanel } from './plugin-post-publish-panel';
export { default as PluginPostStatusInfo } from './plugin-post-status-info';
export { default as PluginPrePublishPanel } from './plugin-pre-publish-panel';
+export { default as PluginPreviewMenuItem } from './plugin-preview-menu-item';
export { default as PluginSidebar } from './plugin-sidebar';
export { default as PluginSidebarMoreMenuItem } from './plugin-sidebar-more-menu-item';
export { default as PostTemplatePanel } from './post-template/panel';
diff --git a/packages/editor/src/components/plugin-preview-menu-item/index.js b/packages/editor/src/components/plugin-preview-menu-item/index.js
new file mode 100644
index 0000000000000..422248e17b88e
--- /dev/null
+++ b/packages/editor/src/components/plugin-preview-menu-item/index.js
@@ -0,0 +1,52 @@
+/**
+ * WordPress dependencies
+ */
+import { compose } from '@wordpress/compose';
+import { MenuItem } from '@wordpress/components';
+import { withPluginContext } from '@wordpress/plugins';
+import { ActionItem } from '@wordpress/interface';
+
+/**
+ * Renders a menu item in the Preview dropdown, which can be used as a button or link depending on the props provided.
+ * The text within the component appears as the menu item label.
+ *
+ * @param {Object} props Component properties.
+ * @param {string} [props.href] When `href` is provided, the menu item is rendered as an anchor instead of a button. It corresponds to the `href` attribute of the anchor.
+ * @param {WPBlockTypeIconRender} [props.icon=inherits from the plugin] The icon to be rendered to the left of the menu item label. Can be a Dashicon slug or an SVG WP element.
+ * @param {Function} [props.onClick] The callback function to be executed when the user clicks the menu item.
+ * @param {...*} [props.other] Any additional props are passed through to the underlying MenuItem component.
+ *
+ * @example
+ * ```jsx
+ * import { __ } from '@wordpress/i18n';
+ * import { PluginPreviewMenuItem } from '@wordpress/editor';
+ * import { external } from '@wordpress/icons';
+ *
+ * function onPreviewClick() {
+ * // Handle preview action
+ * }
+ *
+ * const ExternalPreviewMenuItem = () => (
+ *
+ * { __( 'Preview in new tab' ) }
+ *
+ * );
+ * registerPlugin( 'external-preview-menu-item', {
+ * render: ExternalPreviewMenuItem,
+ * } );
+ * ```
+ *
+ * @return {Component} The rendered menu item component.
+ */
+export default compose(
+ withPluginContext( ( context, ownProps ) => {
+ return {
+ as: ownProps.as ?? MenuItem,
+ icon: ownProps.icon || context.icon,
+ name: 'core/plugin-preview-menu',
+ };
+ } )
+)( ActionItem );
diff --git a/packages/editor/src/components/preview-dropdown/index.js b/packages/editor/src/components/preview-dropdown/index.js
index 6554f7c0228a7..cecf579029a22 100644
--- a/packages/editor/src/components/preview-dropdown/index.js
+++ b/packages/editor/src/components/preview-dropdown/index.js
@@ -22,6 +22,7 @@ import { store as coreStore } from '@wordpress/core-data';
import { useEffect, useRef } from '@wordpress/element';
import { store as preferencesStore } from '@wordpress/preferences';
import { store as blockEditorStore } from '@wordpress/block-editor';
+import { ActionItem } from '@wordpress/interface';
/**
* Internal dependencies
@@ -206,6 +207,11 @@ export default function PreviewDropdown( { forceIsAutosaveable, disabled } ) {
/>
) }
+
>
) }
diff --git a/test/e2e/specs/editor/plugins/plugins-api.spec.js b/test/e2e/specs/editor/plugins/plugins-api.spec.js
index c71b49e3c4d81..c7f3a655e1424 100644
--- a/test/e2e/specs/editor/plugins/plugins-api.spec.js
+++ b/test/e2e/specs/editor/plugins/plugins-api.spec.js
@@ -230,4 +230,25 @@ test.describe( 'Plugins API', () => {
).toBeVisible();
} );
} );
+
+ test.describe( 'Preview Menu Item', () => {
+ test( 'Should render and interact with PluginPreviewMenuItem', async ( {
+ page,
+ } ) => {
+ await page
+ .getByRole( 'region', { name: 'Editor top bar' } )
+ .locator( '.editor-preview-dropdown__toggle' )
+ .click();
+
+ const customPreviewItem = page.getByRole( 'menuitem', {
+ name: 'Custom Preview',
+ } );
+
+ await expect( customPreviewItem ).toBeVisible();
+
+ await customPreviewItem.click();
+
+ await expect( customPreviewItem ).toBeHidden();
+ } );
+ } );
} );