= {
+ name: 'Menu with popover',
+ styles: css``,
+ render(knobs) {
+ return html`
+
+
+
+
+
+
+ This is a popover.
+
+ `;
+ },
+};
+
+export const stories = [menu, menuWithDialog, menuWithPopover];
diff --git a/labs/aria/menu/md-aria-menuitem.ts b/labs/aria/menu/md-aria-menuitem.ts
new file mode 100644
index 0000000000..b59e830ac3
--- /dev/null
+++ b/labs/aria/menu/md-aria-menuitem.ts
@@ -0,0 +1,15 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {AriaMenuitemElement} from './menuitem.js';
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'md-aria-menuitem': AriaMenuitemElement;
+ }
+}
+
+customElements.define('md-aria-menuitem', AriaMenuitemElement);
diff --git a/labs/aria/menu/md-aria-menulist.ts b/labs/aria/menu/md-aria-menulist.ts
new file mode 100644
index 0000000000..2d800e291b
--- /dev/null
+++ b/labs/aria/menu/md-aria-menulist.ts
@@ -0,0 +1,15 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {AriaMenulistElement} from './menulist.js';
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'md-aria-menulist': AriaMenulistElement;
+ }
+}
+
+customElements.define('md-aria-menulist', AriaMenulistElement);
diff --git a/labs/aria/menu/menuitem.ts b/labs/aria/menu/menuitem.ts
new file mode 100644
index 0000000000..9b23b6e589
--- /dev/null
+++ b/labs/aria/menu/menuitem.ts
@@ -0,0 +1,102 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import {consume} from '@lit/context';
+import {CSSResultOrNative, LitElement, css, html} from 'lit';
+import {property} from 'lit/decorators.js';
+import {
+ afterDispatch,
+ setupDispatchHooks,
+} from '../../../internal/events/dispatch-hooks.js';
+import {
+ mixinCustomStateSet,
+ toggleState,
+} from '../../behaviors/custom-state-set.js';
+import {
+ internals,
+ mixinElementInternals,
+} from '../../behaviors/element-internals.js';
+import {mixinFocusable} from '../../behaviors/focusable.js';
+import {sharedCommandInvokerActivationSteps} from '../command.js';
+import {AriaMenulistElement, ancestorMenulistContext} from './menulist.js';
+
+/** Private property key for the `ancestorMenulist` context. */
+const ancestorMenulist = Symbol('ancestorMenulist');
+
+const baseClass = mixinCustomStateSet(
+ mixinFocusable(mixinElementInternals(LitElement)),
+);
+
+/**
+ * An element implementing the proposed `