# 菜单

- 页面: https://jiguang132.com/zh/resources/mantine/docs/menu
- 资源: Mantine Core (https://jiguang132.com/zh/resources/mantine.md)
- 全部指南: https://jiguang132.com/zh/resources/mantine/docs.md

Mantine Core 的独立组件，请不要替换为 JGuang UI/Base UI 的同名 API。

## 安装

```bash
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1
```

入口引入 `@mantine/core/styles.css`，并在根组件使用 `MantineProvider`；通过 `forceColorScheme` 同步深浅色主题。

## 使用与验证

在左侧选择组件，在预览中操作它的状态；使用“查看代码”检查真实源码。安装后执行类型检查和构建，再验证键盘焦点、手机布局与深浅色主题。

## 来源

https://github.com/mantinedev/mantine/tree/f0e2bc6d28b0f0b8aaefb5b859937bf77f539df7
MIT 许可证；不包括付费内容。下方提供上游英文参考内容，中文使用指南已适配；上游详细参考暂保留英文。

---


## 版本与兼容性

固定的 Mantine Core 9.7.1 要求 React 和 React DOM 满足 `^19.2.0`，并配套 `@mantine/hooks@9.7.1`。此条件来自实际 npm 包的 peerDependencies。React 18 或其他不兼容版本不能强行安装；先向项目负责人说明升级影响并确认方案，不使用 --force/--legacy-peer-deps 掩盖冲突。入口的原生 Provider 开启 `theme.respectReducedMotion`，并用 `forceColorScheme` 控制深浅色。

## 适用场景

从触发器展开操作菜单。

## 本地示例使用的原生参数

以下参数由本地、经过类型检查的 JSX 示例提取，按所属组件区分。不是全部属性清单；完整签名和继承关系见下方固定源码参考。

| 组件参数 | 说明 |
| --- | --- |
| `Menu.Item.color` | 原生颜色值或主题颜色键。 |

## 交互与状态检查

当前场景：默认。切换支持的禁用、错误或只读场景后检查真实行为；无此原生状态的组件不会被强行添加统一属性。验证键盘焦点和退出方式，修改值后按原生回调签名连接业务状态。

## 业务接入边界

示例内容和状态仅保存在本地，不提供服务端持久化、授权或数据请求。静态展示组件不应被当作已完成的业务流程。

## 宿主配置

先安装固定版本 @mantine/core 和 @mantine/hooks，在入口引入 @mantine/core/styles.css，并使用 MantineProvider。示例的 theme 和 variant 是 JGuang 编写的宿主参数，不是所有原生组件都接受的统一 API；通过 forceColorScheme 同步应用主题。源码面板中的原生实现仅供阅读，使用 npm 导出，不要单独复制内部实现。此批只覆盖 Core，不包括日期、图表和表单扩展包。上游详细说明保留英文，不宣称全文中文化。


## 可运行用法

以下代码使用资源原生 API；不是把其他设计系统的同名组件替换进来。

```tsx
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {

return <M.Menu><M.Menu.Target><M.Button>Open menu</M.Button></M.Menu.Target><M.Menu.Dropdown><M.Menu.Item>Settings</M.Menu.Item><M.Menu.Item>Profile</M.Menu.Item><M.Menu.Divider /><M.Menu.Item color="red">Delete</M.Menu.Item></M.Menu.Dropdown></M.Menu>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

```


## 可用状态与示例

默认

示例遵循 Mantine 原生 API。支持多状态的输入组件可将示例中的 variant 改为 Disabled、Invalid 或 Read only；这些只是示例标签，不是新增的组件属性。改造时保留组件要求的数据、受控值、store 和复合子组件结构。


## Usage



## Submenus



Use `safeAreaPolygon` to keep a submenu open while the cursor moves from the target toward the dropdown.
Pass an object to adjust [Floating UI `safePolygon`](https://floating-ui.com/docs/useHover#safepolygon) options, for example when `offset` creates a larger gap between the target and dropdown.



## Search

`Menu.Search` renders a search input inside the dropdown. Focus stays on the input while
`ArrowUp`/`ArrowDown` move a highlight through items, and `Enter` triggers the highlighted item.
Filtering is controlled by the user – pass `value` and `onChange` and filter `Menu.Item` children
based on the query. By default, the search value is cleared automatically after the menu close
transition completes – disable with `clearSearchOnClose={false}` if you want to preserve the query
between openings.



The same approach works with submenus. To keep a parent visible when a nested item matches,
include the parent in the filtered tree if any of its descendants match the query:



## Checkbox items

`Menu.CheckboxItem` renders a menu item with a check indicator. It works like a regular
[Checkbox](/core/checkbox/) – manage state with `checked`/`onChange` or use `defaultChecked`
for an uncontrolled value. By default, clicking a checkbox item does not close the menu;
set `closeMenuOnClick` on the item (or `closeOnItemClick={false}` on the `Menu`)
to override:



## Checkbox group

Wrap `Menu.CheckboxItem` components in `Menu.CheckboxGroup` to manage multi-select state with a
single `value: string[]` / `onChange` pair (or `defaultValue` for uncontrolled). Each item needs
a `value`. Clicking an item toggles its value in the group.

`Menu.CheckboxItem` can still be used standalone (without a group) with its own `checked` /
`defaultChecked` / `onChange` props. Item-level `checked` and `onChange` also override the group
when both are present.



## Radio items

`Menu.RadioItem` represents a single option inside a `Menu.RadioGroup`. The group manages
the selected value via `value`/`onChange` (or `defaultValue` for uncontrolled). The currently
selected item displays an indicator dot. Like checkbox items, radio items do not close the
menu on click by default:



## Aligning labels of items with and without indicators

Use the `alignItemsLabels` prop on `Menu` to control how indicator slot space is reserved.
This is useful when mixing `Menu.Item` with `Menu.CheckboxItem` or `Menu.RadioItem` and you
want labels to start at the same horizontal position:

- `alignItemsLabels="with-indicators"` (default) – reserves indicator space on `Menu.CheckboxItem`
  and `Menu.RadioItem` only. Regular `Menu.Item` is not padded.
- `alignItemsLabels="all"` – reserves indicator space on every `Menu.Item`, so labels of plain
  items align with checkbox and radio items.
- `alignItemsLabels="none"` – reserves indicator space only on items that currently show an
  indicator. Unchecked checkbox and radio items render without the slot (layout shifts when
  toggled).



## Custom check icon

Use the `checkIcon` prop to replace the default indicator rendered by `Menu.CheckboxItem` and
`Menu.RadioItem`. Setting `checkIcon` on `Menu` applies to all checkbox/radio items in the
dropdown. Setting `checkIcon` on an individual item overrides the menu-level value:



## Type-ahead navigation

When focus is inside the dropdown and `Menu.Search` is not used, pressing a printable character
key moves focus to the next menu item whose label starts with the typed character. Pressing the
same character again cycles through items that start with it. Multiple characters typed in quick
succession (within 500ms) match items whose labels start with the full typed string. Disabled
items are skipped.

## Context menu

Use `Menu.ContextMenu` to open the menu dropdown at the cursor position on right-click.
It replaces `Menu.Target` and wraps the element that should respond to the `contextmenu` event –
the browser's default context menu is suppressed, and the Mantine `Menu.Dropdown` is positioned
at the cursor instead. Right-clicking again repositions the dropdown to the new coordinates.
Set `disabled` to restore the browser's default context menu:



### Touch devices

On touch devices (most notably iOS Safari, which does not fire the `contextmenu` event),
the dropdown is opened with a long-press instead. Use the `longPressDelay` prop to control
how long the element must be pressed before the dropdown opens, `500`ms by default:

```tsx
import { Menu } from '@mantine/core';

function Demo() {
  return (
    <Menu>
      <Menu.ContextMenu longPressDelay={400}>
        <div>Long-press me</div>
      </Menu.ContextMenu>
      <Menu.Dropdown>
        <Menu.Item>Copy</Menu.Item>
        <Menu.Item>Paste</Menu.Item>
      </Menu.Dropdown>
    </Menu>
  );
}
```

To prevent the native text-selection callout from appearing under the dropdown on touch
devices, `Menu.ContextMenu` disables text selection (`user-select: none`) on the wrapped
element.

## Controlled

The dropdown's opened state can be controlled with the `opened` and `onChange` props:

```tsx
import { useState } from 'react';
import { Menu } from '@mantine/core';

function Demo() {
  const [opened, setOpened] = useState(false);
  return (
    <Menu opened={opened} onChange={setOpened}>
      {/* Menu content */}
    </Menu>
  );
}
```

## Show menu on hover

Set `trigger="hover"` to reveal the dropdown when hovering over the menu target and dropdown.
The `closeDelay` and `openDelay` props can be used to control open and close delay in ms.
Note that:

- If you set `closeDelay={0}` then the menu will close before the user reaches the dropdown, so set `offset={0}` to remove space between the target element and dropdown.
- Menu with `trigger="hover"` is not accessible – users that navigate with the keyboard will not be able to use it. If you need both hover and click triggers, use `trigger="click-hover"`.



To make a `Menu` that is revealed on hover accessible on all devices, use `trigger="click-hover"` instead.
The dropdown will be revealed on hover on desktop and on click on mobile devices.



## Disabled items



## Dropdown position



## Transitions

The Menu dropdown can be animated with any of the premade transitions from the [Transition](/core/transition/) component:



## Custom component as Menu.Item

By default, `Menu.Item` renders as a button element. To change that, set the `component` prop:



Note that the component you pass to the `component` prop should allow spreading props to its root element:

```tsx
import { Menu } from '@mantine/core';

// ❌ Will not work with Menu.Item
function IncorrectItem() {
  return <button type="button">My custom Menu item</button>;
}

// ✅ Will work correctly with Menu.Item
const CorrectItem = ({ ref, ...props }) => (
  <button type="button" {...props} ref={ref}>
    My custom Menu item
  </button>
);

function Demo() {
  // ❌ Will not work
  const incorrect = <Menu.Item component={IncorrectItem} />;

  // ✅ Will work
  const correct = <Menu.Item component={CorrectItem} />;
}
```

## Custom component as target







## Accessibility

Menu follows [WAI-ARIA recommendations](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/examples/menu-button-links/):

- Dropdown element has `role="menu"` and `aria-labelledby="target-id"` attributes
- Target element has `aria-haspopup="menu"`, `aria-expanded`, `aria-controls="dropdown-id"` attributes
- Menu item has `role="menuitem"` attribute

Whilst the dropdown is unopened, the `aria-controls` attribute will be undefined

### Supported target elements

An uncontrolled Menu with `trigger="click"` (default) will be accessible only when used with a `button` element or component that renders it ([Button](/core/button/), [ActionIcon](/core/action-icon/), etc.).
Other elements will not support `Space` and `Enter` key presses.

### Hover menu

Menu with `trigger="hover"` is not accessible – it cannot be accessed with the keyboard. Use it only if you do not care about accessibility. If you need both hover and click triggers, use `trigger="click-hover"`.

### Navigation

If you are using the Menu to build navigation, you can use the options from the demo below to follow the [WAI-ARIA recommendations for navigation](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-navigation/).



### Keyboard interactions


If you also need to support `Tab` and `Shift + Tab` then set `menuItemTabIndex={0}`.


## 源码参数参考

以下实现签名和类型从本地固定版本源码生成。保留可选属性、原生继承类型、联合分支和 never 限制；不会将其他设计系统的 API 混入。forwardRef 实现中的 ref 属于 React 引用，不是新增业务属性。此区域是原始类型参考，不是上游说明的全文翻译。


```ts
Menu(_props)
```



```ts
export type MenuStylesNames =
  | 'item'
  | 'itemLabel'
  | 'itemSection'
  | 'itemIndicator'
  | 'label'
  | 'divider'
  | 'chevron'
  | 'search'
  | PopoverStylesNames;

export type MenuFactory = Factory<{
  props: MenuProps;
  stylesNames: MenuStylesNames;
  staticComponents: {
    Item: typeof MenuItem;
    Label: typeof MenuLabel;
    Dropdown: typeof MenuDropdown;
    Target: typeof MenuTarget;
    Divider: typeof MenuDivider;
    Search: typeof MenuSearch;
    Sub: typeof MenuSub;
    CheckboxItem: typeof MenuCheckboxItem;
    CheckboxGroup: typeof MenuCheckboxGroup;
    RadioItem: typeof MenuRadioItem;
    RadioGroup: typeof MenuRadioGroup;
    ContextMenu: typeof MenuContextMenu;
  };
}>;

export interface MenuProps extends __PopoverProps, StylesApiProps<MenuFactory> {
  variant?: string;

  /** Menu children */
  children?: React.ReactNode;

  /** Controlled menu opened state */
  opened?: boolean;

  /** Uncontrolled menu initial opened state */
  defaultOpened?: boolean;

  /** If set, focus is trapped within the menu dropdown when it is opened */
  trapFocus?: boolean;

  /** Called when menu opened state changes */
  onChange?: (opened: boolean) => void;

  /** Called when Menu is opened */
  onOpen?: () => void;

  /** Called when Menu is closed */
  onClose?: () => void;

  /** If set, the Menu is closed when one of the items is clicked. Can be overridden per item with `closeMenuOnClick` prop */
  closeOnItemClick?: boolean;

  /** If set, arrow key presses wrap around from last item to first and vice versa */
  loop?: boolean;

  /** If set, the dropdown is closed when the `Escape` key is pressed @default true */
  closeOnEscape?: boolean;

  /** Event trigger to open menu. Note: 'hover' is not keyboard accessible; prefer 'click-hover' for accessible hover menus */
  trigger?: 'click' | 'hover' | 'click-hover';

  /** Open delay in ms, applicable only to `trigger="hover"` variant */
  openDelay?: number;

  /** Close delay in ms, applicable only to `trigger="hover"` variant */
  closeDelay?: number;

  /** If set, the dropdown is closed on outside clicks */
  closeOnClickOutside?: boolean;

  /** Events that trigger outside click detection. Includes mousedown for desktop clicks, touchstart for mobile, and keydown for Escape key handling @default ['mousedown', 'touchstart', 'keydown'] */
  clickOutsideEvents?: string[];

  /** Id base to create accessibility connections */
  id?: string;

  /** Set the `tabindex` on all menu items. Use `0` to allow Tab key navigation through menu items (required for navigation menus following WAI-ARIA disclosure pattern). @default -1 */
  menuItemTabIndex?: -1 | 0;

  /** Adds a hidden focusable element at the start of the dropdown to prevent unexpected focus jumps when opening with keyboard. Set to false if you need custom focus management. @default true */
  withInitialFocusPlaceholder?: boolean;

  /** Determines whether focus should be automatically returned to control when dropdown closes @default `true` */
  returnFocus?: boolean;

  /** Controls how indicator slot space is reserved on menu items for label alignment. `'all'` reserves space on every `Menu.Item`, `'with-indicators'` reserves space only on `Menu.CheckboxItem` and `Menu.RadioItem`, `'none'` reserves space only on items that currently display an indicator. @default 'with-indicators' */
  alignItemsLabels?: 'all' | 'with-indicators' | 'none';

  /** Custom icon rendered as the indicator of checked `Menu.CheckboxItem` and selected `Menu.RadioItem`. Can be overridden per item with the `checkIcon` prop. */
  checkIcon?: React.ReactNode;
}
```


### 原生与外部类型

以下外部类型仍由 React 或资源自身依赖定义，没有手工展开为虚构属性。实际可用类型以安装版本的 TypeScript 检查为准。


```ts
Factory<{
  props: MenuProps;
  stylesNames: MenuStylesNames;
  staticComponents: {
    Item: typeof MenuItem;
    Label: typeof MenuLabel;
    Dropdown: typeof MenuDropdown;
    Target: typeof MenuTarget;
    Divider: typeof MenuDivider;
    Search: typeof MenuSearch;
    Sub: typeof MenuSub;
    CheckboxItem: typeof MenuCheckboxItem;
    CheckboxGroup: typeof MenuCheckboxGroup;
    RadioItem: typeof MenuRadioItem;
    RadioGroup: typeof MenuRadioGroup;
    ContextMenu: typeof MenuContextMenu;
  };
}>
__PopoverProps
StylesApiProps<MenuFactory>
React.ReactNode
PopoverStylesNames
```

---

JGuang 全部资源索引: https://jiguang132.com/llms.txt
