# Menu

Import: `import { Menu } from '@neo4j-ndl/react'`

## Props

### Menu

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `anchorRef` | `RefObject<HTMLElement \| null>` |  |  | Anchor element ref for positioning |
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  | Content displayed inside the menu |
| `description` | `ReactNode` |  |  | Optional description for nested trigger rendering |
| `icon` | `ReactNode` |  |  | Optional icon for nested trigger rendering |
| `isDisabled` | `boolean` |  |  | Whether the menu trigger is disabled |
| `isOpen` | `boolean` |  |  | Whether the menu is open or closed (uncontrolled when omitted) |
| `isPortaled` | `boolean` |  | `true` | Whether the menu should be wrapped in a floating portal |
| `isRoot` | `boolean` |  |  | Whether the menu is a root menu instance. This is set internally by the component based on nesting |
| `minWidth` | `number` |  |  | Minimum width in pixels for the menu component |
| `onClose` | `((event: Event, closeReason: { type: "backdropClick" \| "itemClick" \| "escapeKeyDown" \| "focusOut"; id?: string; }) => void) \| undefined` |  |  | Callback function that is called when the menu closes |
| `placement` | `'bottom-end-bottom-start' \| 'bottom-end-top-end' \| 'bottom-middle-top-middle' \| 'bottom-start-bottom-end' \| 'bottom-start-top-start' \| 'middle-end-middle-start' \| 'middle-start-middle-end' \| 'top-end-bottom-end' \| 'top-end-top-start' \| 'top-middle-bottom-middle' \| 'top-start-bottom-start' \| 'top-start-top-end'` |  |  | The placement of the floating element is determined by two sets of words. The first set of words specifies the point on the anchor element where the floating element will be attached. The second set of coordinates specifies the point on the floating element that will attach to the anchor element. |
| `portalTarget` | `HTMLElement \| null` |  |  | Portal target element (defaults to `document.body`) |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `strategy` | `'absolute' \| 'fixed'` |  |  | Positioning strategy used by Floating UI |
| `title` | `string` |  |  | Optional title for nested trigger rendering |

`isRoot` is determined internally by checking for a parent context menu. If no parent exists, the component renders as the root menu; otherwise, a nested menu item trigger is rendered. When `isRoot` is `false`, the `title`, `description`, `icon`, and `isDisabled` props are forwarded to the nested menu item trigger component.

The `placement` prop defaults to `bottom-start` when it is the root menu and `right-start` when it is a nested menu item trigger.

The `strategy` prop is set to `fixed` when the context menu is inside a `Dialog` otherwise it is set to `absolute`.

### Menu.CategoryItem

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  | Content displayed inside the category item component |
| `ref` | `any` |  |  | A ref to apply to the root element. |

### Menu.Divider

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `orientation` | `'horizontal' \| 'vertical'` |  | `horizontal` |  |
| `ref` | `any` |  |  | A ref to apply to the root element. |

### Menu.Group

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` |  |  | Content displayed inside the group. |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |

### Menu.Item

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  | Content displayed inside the menu item component |
| `description` | `ReactNode` |  |  | Supporting text below title |
| `id` | `string` |  |  | Unique identifier for the menu item |
| `isDisabled` | `boolean` |  |  | Whether the menu item is disabled |
| `leadingVisual` | `ReactNode` |  |  | Leading icon for the menu item component |
| `onClick` | `(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void` |  |  | Callback function that is called when the menu item is clicked and it closes the menu tree |
| `onFocus` | `(event: FocusEvent<HTMLButtonElement, Element>) => void` |  |  | Callback function that is called when the menu item is focused |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `title` | `ReactNode` | ✅ |  | Title of the menu item component |
| `trailingContent` | `ReactNode` |  |  |  |

### Menu.Items

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  | Content displayed inside the menu items component |
| `ref` | `any` |  |  | A ref to apply to the root element. |

### Menu.RadioItem

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  | Content displayed inside the menu item component |
| `description` | `ReactNode` |  |  | Supporting text below title |
| `id` | `string` |  |  | Unique identifier for the menu item |
| `isChecked` | `boolean` |  | `false` | Whether the radio item is checked. Marks the item as aria-checked. |
| `isDisabled` | `boolean` |  |  | Whether the menu item is disabled |
| `leadingVisual` | `ReactNode` |  |  | Leading icon for the menu item component |
| `onClick` | `(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void` |  |  | Callback function that is called when the menu item is clicked and it closes the menu tree |
| `onFocus` | `(event: FocusEvent<HTMLButtonElement, Element>) => void` |  |  | Callback function that is called when the menu item is focused |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `title` | `ReactNode` | ✅ |  | Title of the menu item component |
| `trailingContent` | `ReactNode` |  |  |  |

## Accessibility

## Keyboard interactions

Implements the keyboard interactions defined in the [WAI-ARIA menu pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu/).

| Key | Description |
|-----|-------------|
| `ArrowDown` | Moves focus to the next menu item |
| `ArrowUp` | Moves focus to the previous menu item |
| `ArrowRight` | Opens a submenu when focus is on a nested menu item |
| `ArrowLeft` | Closes the current submenu and returns focus to the parent item |
| `Enter` | Activates the focused menu item |
| `Space` | Activates the focused menu item |
| `Tab` | Closes the menu and moves focus to the next focusable element on the page |
| `Shift + Tab` | Closes the menu and moves focus to the previous focusable element on the page |
| `Escape` | Closes the menu and returns focus to the trigger |
| Type-ahead | Typing a character moves focus to the next item starting with that character |

## WAI-ARIA roles and attributes

The Menu component follows the [WAI-ARIA menu pattern](https://www.w3.org/WAI/ARIA/apg/patterns/menu/).

- The menu container has `role="menu"`
- Menu items have `role="menuitem"`
- `Menu.RadioItem` has `role="menuitemradio"` and `aria-checked`
- `Menu.Group` has `role="group"`
- Nested menu triggers have `role="menuitem"` and manage `aria-expanded` internally
- When the menu opens, focus moves to the first item. When it closes, focus returns to the trigger
- The menu closes when focus leaves the menu area

## Implementation guidelines

- If using a button as a trigger, set `aria-haspopup="menu"` and `aria-expanded` on the trigger button
- When mixing `Menu.RadioItem` with regular items, use `Menu.Group` to separate them. This creates the correct grouping semantics for assistive technologies.
- Only one `Menu.RadioItem` within a group should have `isChecked` set to `true` at a time
- Ensure menu items have descriptive `title` values. These are used for both the visible label and the type-ahead search.
- `role="menu"` only allows children with roles `menuitem`, `menuitemradio`, `menuitemcheckbox`, `group`, or `separator`. The built-in sub-components handle this automatically, but custom content passed without a valid role will break the menu semantics for assistive technologies

### Related WCAG criteria

- [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html) (A): All menu items and submenus are fully operable via keyboard
- [2.4.3 Focus Order](https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html) (A): Focus is managed automatically — first item on open, trigger on close
- [4.1.2 Name, Role, Value](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html) (A): Roles (`menu`, `menuitem`, `menuitemradio`, `group`), states (`aria-checked`, `aria-expanded`), and accessible names are set automatically by the component

## Examples

### Default

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'default-menu' }}
      >
        <Menu.Item
          title="Action 1"
          onClick={() => {
            alert('Action1');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          title="Action 2"
          onClick={() => {
            alert('Action2');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          title="Action 3"
          description="Action 3 is disabled"
          isDisabled={true}
          onClick={() => {
            alert('Action3');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          title="Action 4"
          description="Action 4 is awesome"
          onClick={() => {
            alert('Action4');
            setIsOpen(false);
          }}
        />
      </Menu>

      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### Custom Items

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu, Typography } from '@neo4j-ndl/react';
import { Square2StackIconOutline } from '@neo4j-ndl/react/icons';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        placement="bottom-start-top-start"
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'custom-items-menu' }}
      >
        <Menu.Item
          title={
            <Typography variant="display">This can be any element</Typography>
          }
        />
        <Menu.Item title="Danger action 1" className="n-text-danger-text" />
        <Menu.Item
          title="Danger action 2"
          className="n-text-danger-text"
          leadingVisual={
            <Square2StackIconOutline className="n-text-danger-icon" />
          }
        />
        <Menu title="More actions" description="Some additional actions">
          <Menu.Item
            title="Danger action 3"
            className="n-text-danger-text"
            isDisabled={true}
          />
          <Menu.Item title="Danger action 4" className="n-text-danger-text" />
        </Menu>
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu (set with custom placement)
      </FilledButton>
    </>
  );
};

export default Component;
```

### In Dialog

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Dialog, FilledButton, Menu } from '@neo4j-ndl/react';
import { Square2StackIconOutline } from '@neo4j-ndl/react/icons';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [isModalOpen, setIsModalOpen] = useState(false);

  const handleClick = () => setIsModalOpen((prev) => !prev);
  const handleClose = () => setIsModalOpen(false);
  const handleMenuClick = () => setIsOpen((prev) => !prev);

  return (
    <>
      <div className="n-flex n-justify-center">
        <FilledButton onClick={handleClick}>Open Dialog</FilledButton>
      </div>
      <Dialog
        htmlAttributes={{ id: 'modal-root' }}
        isOpen={isModalOpen}
        onClose={handleClose}
      >
        <div className="n-flex n-justify-center">
          <FilledButton
            onClick={handleMenuClick}
            ref={anchorEl}
            aria-haspopup="menu"
            aria-expanded={isOpen}
          >
            Open Menu
          </FilledButton>
        </div>
        <Menu
          isOpen={isOpen}
          anchorRef={anchorEl}
          onClose={(event, _data) => {
            setIsOpen(false);
            event?.preventDefault();
            event?.stopPropagation();
          }}
          portalTarget={document.getElementById('modal-root')}
          htmlAttributes={{ id: 'dialog-menu' }}
        >
          <Menu.Item title="Undo" onClick={() => alert('Undo')} />
          <Menu.Item title="Redo" isDisabled />
          <Menu.Item title="Cut" description="Copy and remove" />
          <Menu
            title="Copy as"
            description="Copying as something"
            icon={<Square2StackIconOutline />}
          >
            <Menu.Item title="Text" />
            <Menu.Item title="Video" />
            <Menu title="Image">
              <Menu.Item title=".png" />
              <Menu.Item title=".jpg" />
              <Menu.Item title=".svg" />
              <Menu.Item title=".gif" />
            </Menu>
            <Menu.Item title="Audio" />
            <Menu title="Share">
              <Menu.Item title="Mail" />
              <Menu.Item title="Instagram" />
            </Menu>
          </Menu>
        </Menu>
      </Dialog>
    </>
  );
};

export default Component;
```

### In Popover

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu, Popover } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [isPopoverOpen, setIsPopoverOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'popover-menu' }}
      >
        <Menu.Item title="Action 1" onClick={() => alert('Action1')} />
        <Menu.Item title="Action 2" onClick={() => alert('Action2')} />
        <Menu.Item
          title="Action 3"
          description="Action 3 is disabled"
          isDisabled={true}
          onClick={() => alert('Action3')}
        />
        <Menu.Item
          title="Action 4"
          description="Action 4 is awesome"
          onClick={() => alert('Action4')}
        />
      </Menu>

      <Popover isOpen={isPopoverOpen}>
        <Popover.Trigger>
          <FilledButton onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
            {isPopoverOpen ? 'Close' : 'Open'} Popover
          </FilledButton>
        </Popover.Trigger>
        <Popover.Content style={{ height: 150, overflow: 'auto', width: 400 }}>
          <>
            <p>
              Scroll me to the bottom to open menu Lorem ipsum dolor sit amet,
              consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
              labore et dolore magna aliqua. Ut enim ad minim veniam, quis
              nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
              consequat. Duis aute irure dolor in reprehenderit in voluptate
              velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
              occaecat cupidatat non proident, sunt in culpa qui officia
              deserunt mollit anim id est laborum.
            </p>
            <FilledButton
              onClick={() => setIsOpen(true)}
              ref={anchorEl}
              aria-haspopup="menu"
              aria-expanded={isOpen}
            >
              Open Context Menu
            </FilledButton>
          </>
        </Popover.Content>
      </Popover>
    </>
  );
};

export default Component;
```

### Nested

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { Square2StackIconOutline } from '@neo4j-ndl/react/icons';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'nested-menu' }}
      >
        <Menu.Item title="Undo" onClick={() => alert('Undo')} />
        <Menu.Item title="Redo" isDisabled />
        <Menu.Item title="Cut" description="Copy and remove" />
        <Menu
          title="Copy as"
          description="Copying as something"
          icon={<Square2StackIconOutline />}
        >
          <Menu.Item title="Text" />
          <Menu.Item title="Video" />
          <Menu title="Image">
            <Menu.Item title=".png" />
            <Menu.Item title=".jpg" />
            <Menu.Item title=".svg" />
            <Menu.Item title=".gif" />
          </Menu>
          <Menu.Item title="Audio" />
        </Menu>
        <Menu title="Share">
          <Menu.Item title="Mail" />
          <Menu.Item title="Instagram" />
        </Menu>
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### Placements

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        placement="middle-end-middle-start"
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'placements-menu' }}
      >
        <Menu.Item
          title="Action 1"
          onClick={() => {
            alert('Action1');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          title="Action 2"
          onClick={() => {
            alert('Action2');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          title="Action 3"
          description="Action 3 is disabled"
          isDisabled={true}
          onClick={() => {
            alert('Action3');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          title="Action 4"
          description="Action 4 is awesome"
          onClick={() => {
            alert('Action4');
            setIsOpen(false);
          }}
        />
        <Menu.Item
          id="action_5"
          title="Action 5"
          description="Action 5 does not close the menu"
        />
      </Menu>

      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### Radio And Normal

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { DropdownButton, Menu, Typography } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [selectedOption, setSelectedOption] = useState<string | null>(
    'option-1',
  );

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'radio-and-normal-menu' }}
      >
        <Menu.Group>
          <Menu.RadioItem
            title="Option 1"
            isChecked={selectedOption === 'option-1'}
            onClick={() => {
              setSelectedOption('option-1');
            }}
          />
          <Menu.RadioItem
            title="Option 2"
            isChecked={selectedOption === 'option-2'}
            onClick={() => {
              setSelectedOption('option-2');
            }}
          />
        </Menu.Group>
        <Menu.Divider />
        <Menu.Group>
          <Menu.Item
            title="Action 1"
            onClick={() => {
              alert('Action 1');
            }}
          />
          <Menu.Item
            title="Action 2"
            onClick={() => {
              alert('Action 2');
            }}
          />
        </Menu.Group>
      </Menu>
      <div className="n-flex n-flex-col n-gap-token-4 n-items-center">
        <Typography variant="body-medium">
          Selected option: <strong>{selectedOption}</strong>
        </Typography>
        <DropdownButton
          isOpen={isOpen}
          onClick={() => setIsOpen(true)}
          ref={anchorEl}
          aria-haspopup="menu"
        >
          Open menu
        </DropdownButton>
      </div>
    </>
  );
};

export default Component;
```

### Radio Items

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { DropdownButton, Kbd, Menu, Typography } from '@neo4j-ndl/react';
import { MoonIconOutline, SunIconOutline } from '@neo4j-ndl/react/icons';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);
  const [selectedOption, setSelectedOption] = useState<string | null>(
    'option-1',
  );

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'radio-items-menu' }}
      >
        <Menu.RadioItem
          title="Option 1"
          leadingVisual={<SunIconOutline />}
          isChecked={selectedOption === 'option-1'}
          onClick={() => {
            setSelectedOption('option-1');
          }}
        />
        <Menu.RadioItem
          title="Option 2"
          leadingVisual={<MoonIconOutline />}
          isChecked={selectedOption === 'option-2'}
          onClick={() => {
            setSelectedOption('option-2');
          }}
        />
        <Menu.RadioItem
          title="Option 3"
          description="Option 3 has a description"
          isChecked={selectedOption === 'option-3'}
          onClick={() => {
            setSelectedOption('option-3');
          }}
        />
        <Menu.RadioItem
          title="Option 4"
          trailingContent={<Kbd keys={['A']} />}
          isChecked={selectedOption === 'option-4'}
          onClick={() => {
            setSelectedOption('option-4');
          }}
        />
      </Menu>
      <div className="n-flex n-flex-col n-gap-token-4 n-items-center">
        <Typography variant="body-medium">
          Selected option: <strong>{selectedOption}</strong>
        </Typography>
        <DropdownButton
          isOpen={isOpen}
          onClick={() => setIsOpen(true)}
          ref={anchorEl}
          aria-haspopup="menu"
        >
          Open menu
        </DropdownButton>
      </div>
    </>
  );
};

export default Component;
```

### With Category

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'category-menu' }}
      >
        <Menu.Group>
          <Menu.CategoryItem>Category 1</Menu.CategoryItem>
          <Menu.Item title="Action 1" onClick={() => alert('Action1')} />
          <Menu.Item title="Action 2" onClick={() => alert('Action2')} />
        </Menu.Group>
        <Menu.Divider />
        <Menu.Group>
          <Menu.Item
            title="Action 3"
            description="Action 3 is disabled"
            isDisabled={true}
            onClick={() => alert('Action3')}
          />
          <Menu.Item
            title="Action 4"
            description="Action 4 is awesome"
            onClick={() => alert('Action4')}
          />
        </Menu.Group>
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### With Disabled Item

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'disabled-item-menu' }}
      >
        <Menu.Item
          title="Action 1"
          description="Action 1 is disabled"
          isDisabled={true}
        />
        <Menu.Item title="Action 2" onClick={() => alert('Action2')} />
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### With Divider

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'divider-menu' }}
      >
        <Menu.Item title="Action 1" />
        <Menu.Divider />
        <Menu.Item title="Action 2" />
        <Menu.Divider />
        <Menu.Item title="Action 3" />
        <Menu.Divider />
        <Menu.Item title="Action 4" />
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### With Icon

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Menu } from '@neo4j-ndl/react';
import { PhotoIconOutline, PlusIconOutline } from '@neo4j-ndl/react/icons';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'icon-menu' }}
      >
        <Menu.Item
          leadingVisual={<PlusIconOutline />}
          title="Action 1"
          onClick={() => alert('Action1')}
        />
        <Menu.Item
          leadingVisual={<PlusIconOutline />}
          title="Action 2"
          onClick={() => alert('Action2')}
        />
        <Menu.Item
          leadingVisual={<PlusIconOutline />}
          title="Action 3"
          description="Action 3 is disabled"
          isDisabled={true}
          onClick={() => alert('Action3')}
        />
        <Menu
          title="Action 3.1"
          description="Action with sub menu"
          icon={<PlusIconOutline />}
        >
          <Menu.Item title="Text" />
          <Menu.Item title="Video" />
          <Menu title="Image" icon={<PhotoIconOutline />}>
            <Menu.Item title=".png" />
            <Menu.Item title=".jpg" />
          </Menu>
          <Menu.Item title="Audio" />
        </Menu>
        <Menu.Item
          leadingVisual={<PlusIconOutline />}
          title="Action 4"
          description="Action 4 is awesome"
          onClick={() => alert('Action4')}
        />
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```

### With Keyboard Shortcuts

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, Kbd, Menu } from '@neo4j-ndl/react';
import { PlusIconOutline } from '@neo4j-ndl/react/icons';
import { useRef, useState } from 'react';

const Component = () => {
  const anchorEl = useRef<HTMLButtonElement | null>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Menu
        isOpen={isOpen}
        anchorRef={anchorEl}
        onClose={(_event, _data) => {
          setIsOpen(false);
        }}
        htmlAttributes={{ id: 'keyboard-shortcuts-menu' }}
      >
        <Menu.Item
          leadingVisual={<PlusIconOutline />}
          title="Action 1"
          onClick={() => alert('Action1')}
        />
        <Menu.Item
          leadingVisual={<PlusIconOutline />}
          trailingContent={<Kbd keys={['A', ['B']]} />}
          title="Action 2"
          description="Action 4 has a keyboard shortcut"
          onClick={() => alert('Action4')}
        />
      </Menu>
      <FilledButton
        onClick={() => setIsOpen(true)}
        ref={anchorEl}
        aria-haspopup="menu"
        aria-expanded={isOpen}
      >
        Open Menu
      </FilledButton>
    </>
  );
};

export default Component;
```
