# 菜单栏

一种在桌面应用程序中常见的可视持久菜单，它提供对一组一致命令的快速访问。

## Features

- 可控或非受控。

- 支持具有可配置阅读方向的子菜单。

- 支持项、标签、项组。

- 支持可勾选项（单个或多个）。

- 自定义侧面、对齐、偏移量、碰撞处理。

- 可选择性地渲染指向箭头。

- 焦点完全管理。

- 完整的键盘导航。

- 支持提前输入。

## [构造](#构造)

导入所有部件并将它们组合在一起。

```jsx
import { Menubar } from "radix-ui";

export default () => (
  <Menubar.Root>
    <Menubar.Menu>
      <Menubar.Trigger />

      <Menubar.Portal>
        <Menubar.Content>
          <Menubar.Label />

          <Menubar.Item />

          <Menubar.Group>
            <Menubar.Item />
          </Menubar.Group>

          <Menubar.CheckboxItem>
            <Menubar.ItemIndicator />
          </Menubar.CheckboxItem>

          <Menubar.RadioGroup>
            <Menubar.RadioItem>
              <Menubar.ItemIndicator />
            </Menubar.RadioItem>
          </Menubar.RadioGroup>

          <Menubar.Sub>
            <Menubar.SubTrigger />

            <Menubar.Portal>
              <Menubar.SubContent />
            </Menubar.Portal>
          </Menubar.Sub>

          <Menubar.Separator />

          <Menubar.Arrow />
        </Menubar.Content>
      </Menubar.Portal>
    </Menubar.Menu>
  </Menubar.Root>
);
```

## [API 参考](#api-参考)

### [Root](#root)

包含菜单栏的所有部分。

| Prop            | Type       | Default          |
| --------------- | ---------- | ---------------- |
| `asChild`       | `boolean`  | `false`          |
| `defaultValue`  | `string`   | No default value |
| `value`         | `string`   | No default value |
| `onValueChange` | `function` | No default value |
| `dir`           | `enum`     | No default value |
| `loop`          | `boolean`  | `false`          |

### [Menu](#menu)

顶级菜单项，包含触发器与内容组合。

| Prop      | Type      | Default          |
| --------- | --------- | ---------------- |
| `asChild` | `boolean` | `false`          |
| `value`   | `string`  | No default value |

### [Trigger](#trigger)

切换内容的按钮。默认情况下，`Menubar.Content` 将相对于触发器进行定位。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

| Data attribute       | Values               |
| -------------------- | -------------------- |
| `[data-state]`       | `"open" \| "closed"` |
| `[data-highlighted]` | 当突出显示时存在     |
| `[data-disabled]`    | 当禁用时存在         |

### [Portal](#portal)

当使用时，将内容部分传送到 `body`。

| Prop         | Type          | Default          |
| ------------ | ------------- | ---------------- |
| `forceMount` | `boolean`     | No default value |
| `container`  | `HTMLElement` | `document.body`  |

### [Content](#content)

菜单打开时弹出的组件。

| Prop                   | Type                | Default          |
| ---------------------- | ------------------- | ---------------- |
| `asChild`              | `boolean`           | `false`          |
| `loop`                 | `boolean`           | `false`          |
| `onCloseAutoFocus`     | `function`          | No default value |
| `onEscapeKeyDown`      | `function`          | No default value |
| `onPointerDownOutside` | `function`          | No default value |
| `onFocusOutside`       | `function`          | No default value |
| `onInteractOutside`    | `function`          | No default value |
| `forceMount`           | `boolean`           | No default value |
| `side`                 | `enum`              | `"bottom"`       |
| `sideOffset`           | `number`            | `0`              |
| `align`                | `enum`              | `"center"`       |
| `alignOffset`          | `number`            | `0`              |
| `avoidCollisions`      | `boolean`           | `true`           |
| `collisionBoundary`    | `Boundary`          | `[]`             |
| `collisionPadding`     | `number \| Padding` | `0`              |
| `arrowPadding`         | `number`            | `0`              |
| `sticky`               | `enum`              | `"partial"`      |
| `hideWhenDetached`     | `boolean`           | `false`          |

| Data attribute | Values                                   |
| -------------- | ---------------------------------------- |
| `[data-state]` | `"open" \| "closed"`                     |
| `[data-side]`  | `"left" \| "right" \| "bottom" \| "top"` |
| `[data-align]` | `"start" \| "end" \| "center"`           |

| CSS Variable                               | Description                                    |
| ------------------------------------------ | ---------------------------------------------- |
| `--radix-menubar-content-transform-origin` | 从内容和箭头位置/偏移计算的 `transform-origin` |
| `--radix-menubar-content-available-width`  | 触发器和边界边缘之间的剩余宽度                 |
| `--radix-menubar-content-available-height` | 触发器和边界边缘之间的剩余高度                 |
| `--radix-menubar-trigger-width`            | 触发器的宽度                                   |
| `--radix-menubar-trigger-height`           | 触发器的高度                                   |

### [Arrow](#arrow)

一个可选的箭头元素，可以与菜单栏菜单一起呈现。这可以帮助在视觉上将触发器与 `Menubar.Content` 关联。必须在 `Menubar.Content` 内部呈现。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |
| `width`   | `number`  | `10`    |
| `height`  | `number`  | `5`     |

### [Item](#item)

包含菜单栏项的组件。

| Prop        | Type       | Default          |
| ----------- | ---------- | ---------------- |
| `asChild`   | `boolean`  | `false`          |
| `disabled`  | `boolean`  | No default value |
| `onSelect`  | `function` | No default value |
| `textValue` | `string`   | No default value |

| Data attribute       | Values           |
| -------------------- | ---------------- |
| `[data-highlighted]` | 当突出显示时存在 |
| `[data-disabled]`    | 当禁用时存在     |

### [Group](#group)

用于分组多个 `Menubar.Item`。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

### [Label](#label)

用于呈现标签。无法使用箭头键聚焦。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

### [CheckboxItem](#checkboxitem)

可以控制并呈现为复选框的项。

| Prop              | Type                         | Default          |
| ----------------- | ---------------------------- | ---------------- |
| `asChild`         | `boolean`                    | `false`          |
| `checked`         | `boolean \| 'indeterminate'` | No default value |
| `onCheckedChange` | `function`                   | No default value |
| `disabled`        | `boolean`                    | No default value |
| `onSelect`        | `function`                   | No default value |
| `textValue`       | `string`                     | No default value |

| Data attribute       | Values                     |
| -------------------- | -------------------------- |
| `[data-state]`       | `"checked" \| "unchecked"` |
| `[data-highlighted]` | 当突出显示时存在           |
| `[data-disabled]`    | 当禁用时存在               |

### [RadioGroup](#radiogroup)

用于分组多个 `Menubar.RadioItem`。

| Prop            | Type       | Default          |
| --------------- | ---------- | ---------------- |
| `asChild`       | `boolean`  | `false`          |
| `value`         | `string`   | No default value |
| `onValueChange` | `function` | No default value |

### [RadioItem](#radioitem)

可以控制并呈现为单选的项。

| Prop        | Type       | Default          |
| ----------- | ---------- | ---------------- |
| `asChild`   | `boolean`  | `false`          |
| `value*`    | `string`   | No default value |
| `disabled`  | `boolean`  | No default value |
| `onSelect`  | `function` | No default value |
| `textValue` | `string`   | No default value |

| Data attribute       | Values                     |
| -------------------- | -------------------------- |
| `[data-state]`       | `"checked" \| "unchecked"` |
| `[data-highlighted]` | 当突出显示时存在           |
| `[data-disabled]`    | 当禁用时存在               |

### [ItemIndicator](#itemindicator)

当父 `Menubar.CheckboxItem` 或 `Menubar.RadioItem` 被选中时呈现。您可以直接样式化此元素，或者将其用作放置图标的包装器，或两者兼而有之。

| Prop         | Type      | Default          |
| ------------ | --------- | ---------------- |
| `asChild`    | `boolean` | `false`          |
| `forceMount` | `boolean` | No default value |

| Data attribute | Values                     |
| -------------- | -------------------------- |
| `[data-state]` | `"checked" \| "unchecked"` |

### [Separator](#separator)

用于在菜单栏菜单中视觉上分隔项。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

### [Sub](#sub)

包含子菜单的所有部分。

| Prop           | Type       | Default          |
| -------------- | ---------- | ---------------- |
| `defaultOpen`  | `boolean`  | No default value |
| `open`         | `boolean`  | No default value |
| `onOpenChange` | `function` | No default value |

### [SubTrigger](#subtrigger)

打开子菜单的项。必须在 `Menubar.Sub` 内部呈现。

| Prop        | Type      | Default          |
| ----------- | --------- | ---------------- |
| `asChild`   | `boolean` | `false`          |
| `disabled`  | `boolean` | No default value |
| `textValue` | `string`  | No default value |

| Data attribute       | Values               |
| -------------------- | -------------------- |
| `[data-state]`       | `"open" \| "closed"` |
| `[data-highlighted]` | 当突出显示时存在     |
| `[data-disabled]`    | 当禁用时存在         |

### [SubContent](#subcontent)

子菜单打开时弹出的组件。必须在 `Menubar.Sub` 内部呈现。

| Prop                   | Type                | Default          |
| ---------------------- | ------------------- | ---------------- |
| `asChild`              | `boolean`           | `false`          |
| `loop`                 | `boolean`           | `false`          |
| `onEscapeKeyDown`      | `function`          | No default value |
| `onPointerDownOutside` | `function`          | No default value |
| `onFocusOutside`       | `function`          | No default value |
| `onInteractOutside`    | `function`          | No default value |
| `forceMount`           | `boolean`           | No default value |
| `sideOffset`           | `number`            | `0`              |
| `alignOffset`          | `number`            | `0`              |
| `avoidCollisions`      | `boolean`           | `true`           |
| `collisionBoundary`    | `Boundary`          | `[]`             |
| `collisionPadding`     | `number \| Padding` | `0`              |
| `arrowPadding`         | `number`            | `0`              |
| `sticky`               | `enum`              | `"partial"`      |
| `hideWhenDetached`     | `boolean`           | `false`          |

| Data attribute       | Values                                   |
| -------------------- | ---------------------------------------- |
| `[data-state]`       | `"open" \| "closed"`                     |
| `[data-side]`        | `"left" \| "right" \| "bottom" \| "top"` |
| `[data-align]`       | `"start" \| "end" \| "center"`           |
| `[data-orientation]` | `"vertical" \| "horizontal"`             |

| CSS Variable                               | Description                                    |
| ------------------------------------------ | ---------------------------------------------- |
| `--radix-menubar-content-transform-origin` | 从内容和箭头位置/偏移计算的 `transform-origin` |
| `--radix-menubar-content-available-width`  | 触发器和边界边缘之间的剩余宽度                 |
| `--radix-menubar-content-available-height` | 触发器和边界边缘之间的剩余高度                 |
| `--radix-menubar-trigger-width`            | 触发器的宽度                                   |
| `--radix-menubar-trigger-height`           | 触发器的高度                                   |

## [示例](#示例)

### [带子菜单](#带子菜单)

您可以通过结合使用 `Menubar.Sub` 及其部分来创建子菜单。

```jsx
<Menubar.Root>
  <Menubar.Menu>
    <Menubar.Trigger>…</Menubar.Trigger>

    <Menubar.Portal>
      <Menubar.Content>
        <Menubar.Item>…</Menubar.Item>

        <Menubar.Item>…</Menubar.Item>

        <Menubar.Separator />

        <Menubar.Sub>
          <Menubar.SubTrigger>子菜单 →</Menubar.SubTrigger>

          <Menubar.Portal>
            <Menubar.SubContent>
              <Menubar.Item>子菜单项</Menubar.Item>

              <Menubar.Item>子菜单项</Menubar.Item>

              <Menubar.Arrow />
            </Menubar.SubContent>
          </Menubar.Portal>
        </Menubar.Sub>

        <Menubar.Separator />

        <Menubar.Item>…</Menubar.Item>
      </Menubar.Content>
    </Menubar.Portal>
  </Menubar.Menu>
</Menubar.Root>
```

### [带禁用项](#带禁用项)

您可以通过 `data-disabled` 属性为禁用项添加特殊样式。

```jsx
// index.jsx

import { Menubar } from "radix-ui";

import "./styles.css";

export default () => (
  <Menubar.Root>
    <Menubar.Menu>
      <Menubar.Trigger>…</Menubar.Trigger>

      <Menubar.Portal>
        <Menubar.Content>
          <Menubar.Item className="MenubarItem" disabled>
            …
          </Menubar.Item>

          <Menubar.Item className="MenubarItem">…</Menubar.Item>
        </Menubar.Content>
      </Menubar.Portal>
    </Menubar.Menu>
  </Menubar.Root>
);
```

```css
/* styles.css */

.MenubarItem[data-disabled] {
  color: gainsboro;
}
```

### [带分隔符](#带分隔符)

使用 `Separator` 部件在项之间添加分隔符。

```jsx
<Menubar.Root>
  <Menubar.Menu>
    <Menubar.Trigger>…</Menubar.Trigger>

    <Menubar.Portal>
      <Menubar.Content>
        <Menubar.Item>…</Menubar.Item>

        <Menubar.Separator />

        <Menubar.Item>…</Menubar.Item>

        <Menubar.Separator />

        <Menubar.Item>…</Menubar.Item>
      </Menubar.Content>
    </Menubar.Portal>
  </Menubar.Menu>
</Menubar.Root>
```

### [带标签](#带标签)

使用 `Label` 部件帮助标记一个部分。

```jsx
<Menubar.Root>
  <Menubar.Menu>
    <Menubar.Trigger>…</Menubar.Trigger>

    <Menubar.Portal>
      <Menubar.Content>
        <Menubar.Label>标签</Menubar.Label>

        <Menubar.Item>…</Menubar.Item>

        <Menubar.Item>…</Menubar.Item>

        <Menubar.Item>…</Menubar.Item>
      </Menubar.Content>
    </Menubar.Portal>
  </Menubar.Menu>
</Menubar.Root>
```

### [带复选框项](#带复选框项)

使用 `CheckboxItem` 部件添加可以勾选的项。

```jsx
import * as React from "react";

import { CheckIcon } from "@radix-ui/react-icons";

import { Menubar } from "radix-ui";

export default () => {
  const [checked, setChecked] = React.useState(true);

  return (
    <Menubar.Root>
      <Menubar.Menu>
        <Menubar.Trigger>…</Menubar.Trigger>

        <Menubar.Portal>
          <Menubar.Content>
            <Menubar.Item>…</Menubar.Item>

            <Menubar.Item>…</Menubar.Item>

            <Menubar.Separator />

            <Menubar.CheckboxItem checked={checked} onCheckedChange={setChecked}>
              <Menubar.ItemIndicator>
                <CheckIcon />
              </Menubar.ItemIndicator>
              复选框项
            </Menubar.CheckboxItem>
          </Menubar.Content>
        </Menubar.Portal>
      </Menubar.Menu>
    </Menubar.Root>
  );
};
```

### [带单选项](#带单选项)

使用 `RadioGroup` 和 `RadioItem` 部件添加可以在其他选项之间选择的项。

```jsx
import * as React from "react";

import { CheckIcon } from "@radix-ui/react-icons";

import { Menubar } from "radix-ui";

export default () => {
  const [color, setColor] = React.useState("blue");

  return (
    <Menubar.Root>
      <Menubar.Menu>
        <Menubar.Trigger>…</Menubar.Trigger>

        <Menubar.Portal>
          <Menubar.Content>
            <Menubar.RadioGroup value={color} onValueChange={setColor}>
              <Menubar.RadioItem value="red">
                <Menubar.ItemIndicator>
                  <CheckIcon />
                </Menubar.ItemIndicator>
                红色
              </Menubar.RadioItem>

              <Menubar.RadioItem value="blue">
                <Menubar.ItemIndicator>
                  <CheckIcon />
                </Menubar.ItemIndicator>
                蓝色
              </Menubar.RadioItem>
            </Menubar.RadioGroup>
          </Menubar.Content>
        </Menubar.Portal>
      </Menubar.Menu>
    </Menubar.Root>
  );
};
```

### [带复杂项](#带复杂项)

您可以在 `Item` 部件中添加额外的装饰元素，例如图像。

```jsx
import { Menubar } from "radix-ui";

export default () => (
  <Menubar.Root>
    <Menubar.Menu>
      <Menubar.Trigger>…</Menubar.Trigger>

      <Menubar.Portal>
        <Menubar.Content>
          <Menubar.Item>
            <img src="…" />
            阿道夫·黑斯
          </Menubar.Item>

          <Menubar.Item>
            <img src="…" />
            宫谷·麦尔斯
          </Menubar.Item>
        </Menubar.Content>
      </Menubar.Portal>
    </Menubar.Menu>
  </Menubar.Root>
);
```

### [限制内容/子内容大小](#限制内容子内容大小)

您可能希望限制内容（或子内容）的宽度，以与触发器（或子触发器）宽度匹配。您还可能希望限制其高度，以不超过视口。

我们公开几个 CSS 自定义属性，例如 `--radix-menubar-trigger-width` 和 `--radix-menubar-content-available-height` 来支持此功能。使用它们限制内容尺寸。

```jsx
// index.jsx

import { Menubar } from "radix-ui";

import "./styles.css";

export default () => (
  <Menubar.Root>
    <Menubar.Trigger>…</Menubar.Trigger>

    <Menubar.Portal>
      <Menubar.Content className="MenubarContent" sideOffset={5}>
        …
      </Menubar.Content>
    </Menubar.Portal>
  </Menubar.Root>
);
```

```css
/* styles.css */

.MenubarContent {
  width: var(--radix-menubar-trigger-width);

  max-height: var(--radix-menubar-content-available-height);
}
```

### [原点感知动画](#原点感知动画)

我们公开一个 CSS 自定义属性 `--radix-menubar-content-transform-origin`。使用它根据 `side`、`sideOffset`、`align`、`alignOffset` 和任何碰撞进行内容动画。

```jsx
// index.jsx

import { Menubar } from "radix-ui";

import "./styles.css";

export default () => (
  <Menubar.Root>
    <Menubar.Menu>
      <Menubar.Trigger>…</Menubar.Trigger>

      <Menubar.Portal>
        <Menubar.Content className="MenubarContent">…</Menubar.Content>
      </Menubar.Portal>
    </Menubar.Menu>
  </Menubar.Root>
);
```

```css
/* styles.css */

.MenubarContent {
  transform-origin: var(--radix-menubar-content-transform-origin);

  animation: scaleIn 0.5s ease-out;
}

@keyframes scaleIn {
  from {
    opacity: 0;

    transform: scale(0);
  }

  to {
    opacity: 1;

    transform: scale(1);
  }
}
```

### [碰撞感知动画](#碰撞感知动画)

我们公开 `data-side` 和 `data-align` 属性。它们的值将在运行时更改以反映碰撞。使用它们创建碰撞和方向感知的动画。

```jsx
// index.jsx

import { Menubar } from "radix-ui";

import "./styles.css";

export default () => (
  <Menubar.Root>
    <Menubar.Menu>
      <Menubar.Trigger>…</Menubar.Trigger>

      <Menubar.Portal>
        <Menubar.Content className="MenubarContent">…</Menubar.Content>
      </Menubar.Portal>
    </Menubar.Menu>
  </Menubar.Root>
);
```

```css
/* styles.css */

.MenubarContent {
  animation-duration: 0.6s;

  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

.MenubarContent[data-side="top"] {
  animation-name: slideUp;
}

.MenubarContent[data-side="bottom"] {
  animation-name: slideDown;
}

@keyframes slideUp {
  from {
    opacity: 0;

    transform: translateY(10px);
  }

  to {
    opacity: 1;

    transform: translateY(0);
  }
}

@keyframes slideDown {
  from {
    opacity: 0;

    transform: translateY(-10px);
  }

  to {
    opacity: 1;

    transform: translateY(0);
  }
}
```

## [可访问性](#可访问性)

遵循 [菜单按钮 WAI-ARIA 设计模式](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/) 并使用 [游走的 tabindex](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_roving_tabindex) 来管理菜单项之间的焦点移动。

### [键盘交互](#键盘交互)

| Key                     | Description                                                                                                                                                                                          |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Space`                 | 当焦点位于 `Menubar.Trigger` 时，打开菜单栏并聚焦第一个项。 当焦点位于某个项时，激活该项。                                                                                                           |
| `Enter`                 | 当焦点位于 `Menubar.Trigger` 时，打开相关的菜单。 当焦点位于某个项时，激活该项。                                                                                                                     |
| `ArrowDown`             | 当焦点位于 `Menubar.Trigger` 时，打开相关的菜单。 当焦点位于某个项时，移动焦点到下一个项。                                                                                                           |
| `ArrowUp`               | 当焦点位于某个项时，移动焦点到上一个项。                                                                                                                                                             |
| `ArrowRight``ArrowLeft` | 当焦点位于 `Menubar.Trigger` 时，移动焦点到下一个或上一个项。 当焦点位于 `Menubar.SubTrigger` 时，打开或关闭子菜单，具体取决于阅读方向。 当焦点位于 `Menubar.Content` 时，打开菜单栏中的下一个菜单。 |
| `Esc`                   | 关闭当前打开的菜单，并将焦点移动到其 `Menubar.Trigger`。                                                                                                                                             |

<!--$-->

<!--/$-->
