Lzh on GitHub

Context Menu

显示位于指针处的菜单,通过右键单击或长按触发。
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import {
  ContextMenuCheckboxItem,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuItemIndicator,
  ContextMenuLabel,
  ContextMenuPortal,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuRoot,
  ContextMenuSeparator,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from 'reka-ui'
import { ref } from 'vue'

const checkboxOne = ref(false)
const checkboxTwo = ref(false)
const person = ref('pedro')

function handleClick() {
  // eslint-disable-next-line no-alert
  alert('hello!')
}
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger
      as-child
      class="block border-2 border-stone-700 dark:border-white border-dashed text-stone-700 dark:text-white rounded-xl text-sm select-none py-[45px] w-[300px] text-center"
    >
      <span> Right click here. </span>
    </ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent
        class="min-w-[220px] z-30 bg-white outline-none rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade"
        :side-offset="5"
      >
        <ContextMenuItem
          value="New Tab"
          class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
          @click="handleClick"
        >
          New Tab <div
          class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
        >
          ⌘+T
        </div>
        </ContextMenuItem>
        <ContextMenuSub>
          <ContextMenuSubTrigger
            value="more toolsz"
            class="group w-full text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:bg-green9 data-[highlighted]:data-[state=open]:text-green1"
          >
            More Tools <div
            class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
          >
            <Icon icon="radix-icons:chevron-right" />
          </div>
          </ContextMenuSubTrigger>
          <ContextMenuPortal>
            <ContextMenuSubContent
              class="min-w-[220px] z-30 outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade"
              :side-offset="2"
              :align-offset="-5"
            >
              <ContextMenuItem
                class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Save Page As… <div
                class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
              >
                ⌘+S
              </div>
              </ContextMenuItem>
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Create Shortcut…
              </ContextMenuItem>
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Name Window…
              </ContextMenuItem>
              <ContextMenuSeparator class="h-[1px] bg-green6 m-[5px]" />
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Developer Tools
              </ContextMenuItem>
            </ContextMenuSubContent>
          </ContextMenuPortal>
        </ContextMenuSub>
        <ContextMenuItem
          value="New Window"
          class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
        >
          New Window <div
          class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
        >
          ⌘+N
        </div>
        </ContextMenuItem>
        <ContextMenuItem
          value="New Private Window"
          class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
          disabled
        >
          New Private Window <div
          class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
        >
          ⇧+⌘+N
        </div>
        </ContextMenuItem>
        <ContextMenuSub>
          <ContextMenuSubTrigger
            value="more tools"
            class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none w-full outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:bg-green9 data-[highlighted]:data-[state=open]:text-green1"
          >
            More Tools <div
            class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
          >
            <Icon icon="radix-icons:chevron-right" />
          </div>
          </ContextMenuSubTrigger>
          <ContextMenuPortal>
            <ContextMenuSubContent
              class="min-w-[220px] z-30 outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade"
              :side-offset="2"
              :align-offset="-5"
            >
              <ContextMenuItem
                class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Save Page As… <div
                class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
              >
                ⌘+S
              </div>
              </ContextMenuItem>
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Create Shortcut…
              </ContextMenuItem>
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Name Window…
              </ContextMenuItem>
              <ContextMenuSeparator class="h-[1px] bg-green6 m-[5px]" />
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Developer Tools
              </ContextMenuItem>
              <ContextMenuSub>
                <ContextMenuSubTrigger
                  value="more toolsz"
                  class="group w-full text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:bg-green9 data-[highlighted]:data-[state=open]:text-green1"
                >
                  More Tools <div
                  class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
                >
                  <Icon icon="radix-icons:chevron-right" />
                </div>
                </ContextMenuSubTrigger>
                <ContextMenuPortal>
                  <ContextMenuSubContent
                    class="min-w-[220px] z-30 outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade"
                    :side-offset="2"
                    :align-offset="-5"
                  >
                    <ContextMenuItem
                      class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                    >
                      Save Page As… <div
                      class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
                    >
                      ⌘+S
                    </div>
                    </ContextMenuItem>
                    <ContextMenuItem
                      class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                    >
                      Create Shortcut…
                    </ContextMenuItem>
                    <ContextMenuItem
                      class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                    >
                      Name Window…
                    </ContextMenuItem>
                    <ContextMenuSeparator class="h-[1px] bg-green6 m-[5px]" />
                    <ContextMenuItem
                      class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                    >
                      Developer Tools
                    </ContextMenuItem>
                    <ContextMenuSub>
                      <ContextMenuSubTrigger
                        value="more toolsz"
                        class="group w-full text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:bg-green9 data-[highlighted]:data-[state=open]:text-green1"
                      >
                        More Tools <div
                        class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
                      >
                        <Icon icon="radix-icons:chevron-right" />
                      </div>
                      </ContextMenuSubTrigger>
                      <ContextMenuPortal>
                        <ContextMenuSubContent
                          class="min-w-[220px] z-30 outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade"
                          :side-offset="2"
                          :align-offset="-5"
                        >
                          <ContextMenuItem
                            class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                          >
                            Save Page As… <div
                            class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
                          >
                            ⌘+S
                          </div>
                          </ContextMenuItem>
                          <ContextMenuItem
                            class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                          >
                            Create Shortcut…
                          </ContextMenuItem>
                          <ContextMenuItem
                            class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                          >
                            Name Window…
                          </ContextMenuItem>
                          <ContextMenuSeparator class="h-[1px] bg-green6 m-[5px]" />
                          <ContextMenuItem
                            class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
                          >
                            Developer Tools
                          </ContextMenuItem>
                        </ContextMenuSubContent>
                      </ContextMenuPortal>
                    </ContextMenuSub>
                  </ContextMenuSubContent>
                </ContextMenuPortal>
              </ContextMenuSub>
              <ContextMenuItem
                class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              >
                Developer Tools
              </ContextMenuItem>
            </ContextMenuSubContent>
          </ContextMenuPortal>
        </ContextMenuSub>
        <ContextMenuSeparator class="h-[1px] bg-green6 m-[5px]" />
        <ContextMenuCheckboxItem
          v-model="checkboxOne"
          class="group text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
        >
          <ContextMenuItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
            <Icon icon="radix-icons:check" />
          </ContextMenuItemIndicator> Show Bookmarks <div
          class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
        >
          ⌘+B
        </div>
        </ContextMenuCheckboxItem>
        <ContextMenuCheckboxItem
          v-model="checkboxTwo"
          class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
        >
          <ContextMenuItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
            <Icon icon="radix-icons:check" />
          </ContextMenuItemIndicator> Show Full URLs
        </ContextMenuCheckboxItem>
        <ContextMenuSeparator class="h-[1px] bg-green6 m-[5px]" />
        <ContextMenuLabel class="pl-[25px] text-xs leading-[25px] text-mauve11">
          People
        </ContextMenuLabel>
        <ContextMenuRadioGroup v-model="person">
          <ContextMenuRadioItem
            class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
            value="pedro"
          >
            <ContextMenuItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
              <Icon icon="radix-icons:dot-filled" />
            </ContextMenuItemIndicator> Pedro Duarte
          </ContextMenuRadioItem>
          <ContextMenuRadioItem
            class="text-xs leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[25px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
            value="colm"
          >
            <ContextMenuItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
              <Icon icon="radix-icons:dot-filled" />
            </ContextMenuItemIndicator> Colm Tuite
          </ContextMenuRadioItem>
        </ContextMenuRadioGroup>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

功能特点

  • 支持带可配置阅读方向的子菜单。
  • 支持项目、标签、项目组。
  • 支持可勾选项目(单选或多选),并可选不确定状态。
  • 支持模态和非模态模式。
  • 自定义侧边、对齐方式、偏移量、碰撞处理。
  • 焦点完全管理。
  • 完整的键盘导航。
  • 类型提前支持(Typeahead support)。
  • 关闭和分层行为高度可定制。
  • 在触摸设备上通过长按触发。

安装

从命令行安装组件。

$ npm add reka-ui

结构

导入所有部分并将其组合在一起。

<script setup lang="ts">
  import {
    ContextMenuCheckboxItem,
    ContextMenuContent,
    ContextMenuGroup,
    ContextMenuItem,
    ContextMenuItemIndicator,
    ContextMenuLabel,
    ContextMenuPortal,
    ContextMenuRadioGroup,
    ContextMenuRadioItem,
    ContextMenuRoot,
    ContextMenuSeparator,
    ContextMenuSub,
    ContextMenuSubContent,
    ContextMenuSubTrigger,
    ContextMenuTrigger,
  } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger />
    
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuLabel />
        <ContextMenuItem />
        
        <ContextMenuGroup>
          <ContextMenuItem />
        </ContextMenuGroup>
        
        <ContextMenuCheckboxItem>
          <ContextMenuItemIndicator />
        </ContextMenuCheckboxItem>
        
        <ContextMenuRadioGroup>
          <ContextMenuRadioItem>
            <ContextMenuItemIndicator />
          </ContextMenuRadioItem>
        </ContextMenuRadioGroup>
        
        <ContextMenuSub>
          <ContextMenuSubTrigger />
          <ContextMenuPortal>
            <ContextMenuSubContent />
          </ContextMenuPortal>
        </ContextMenuSub>
        
        <ContextMenuSeparator />
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

API 参考

遵循 Menu WAI-ARIA 设计模式 并使用 漫游 tabindex 来管理菜单项之间的焦点移动。

Root

包含上下文菜单的所有部分。

属性默认值类型描述
dir'ltr' | 'rtl'适用时,组合框的阅读方向。如果省略,则全局继承自 ConfigProvider 或假定为 LTR(从左到右)阅读模式。
modaltrueboolean下拉菜单的模态。当设置为 true 时,与外部元素的交互将被禁用,并且只有菜单内容对屏幕阅读器可见。

触发事件 (Emit)

事件Payload描述
update:open[payload: boolean]子菜单打开状态改变时调用的事件处理程序。

Trigger

打开上下文菜单的区域。将其包裹在您希望上下文菜单在右键单击(或使用相关键盘快捷键)时打开的目标周围。

属性默认值类型描述
as'span'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
disabledfalseboolean当为 true 时,右键单击时不会打开上下文菜单。请注意,这也会恢复原生上下文菜单。

数据属性

属性
[data-state]"open" | "closed"

Portal

当使用时,将内容部分传送到 body 中。

属性默认值类型描述
deferboolean延迟 Teleport 目标的解析,直到应用程序的其他部分挂载(需要 Vue 3.5.0+)。 参考
disabledboolean禁用 Teleport 并内联渲染组件。 参考
forceMountboolean当需要更多控制时,用于强制挂载。在与 Vue 动画库控制动画时很有用。
tostring | HTMLElementVue 原生 Teleport 组件 prop :to参考

Content

在打开的上下文菜单中弹出的组件。

属性默认值类型描述
alignFlipboolean在与边界发生碰撞时翻转对齐方式。仅当 prioritizePositiontrue 时才会发生。
alignOffset0numberstartend 对齐选项的像素偏移量。
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
avoidCollisionstrueboolean当为 true 时,覆盖侧边和对齐偏好以防止与边界边缘碰撞。
collisionBoundary[]Element | (Element | null)[] | null用作碰撞边界的元素。默认情况下是视口,但您可以提供额外的元素以包含在此检查中。
collisionPadding0number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>碰撞检测应发生的边界边缘的像素距离。接受一个数字(所有边相同),或一个部分填充对象,例如:{ top: 20, left: 20 }
disableUpdateOnLayoutShiftboolean是否在布局偏移时禁用内容更新位置。
forceMountboolean当需要更多控制时,用于强制挂载。在与 Vue 动画库控制动画时很有用。
hideWhenDetachedfalseboolean当触发器完全被遮挡时是否隐藏内容。
loopboolean当为 true 时,键盘导航将从最后一个项目循环到第一个,反之亦然。
positionStrategy'fixed' | 'absolute'要使用的 CSS position 属性类型。
prioritizePositionboolean强制内容在视口内定位。可能会与参考元素重叠,这可能不是期望的。
referenceReferenceElement将作为浮动元素定位参考的自定义元素或虚拟元素。如果提供,它将替换默认锚点元素。
sticky'partial''partial' | 'always'对齐轴上的粘性行为。partial 将使内容保持在边界内,只要触发器至少部分在边界内,而 always 将无论如何都使内容保持在边界内。

触发事件 (Emit)

事件名称Payload描述
closeAutoFocus[event: Event]关闭时自动聚焦时调用的事件处理程序。可以阻止。
escapeKeyDown[event: KeyboardEvent]Escape 键按下时调用的事件处理程序。可以阻止。
focusOutside[event: FocusOutsideEvent]焦点移出 DismissableLayer 时调用的事件处理程序。可以阻止。
interactOutside[event: PointerDownOutsideEvent | FocusOutsideEvent]DismissableLayer 外部发生交互时调用的事件处理程序。具体来说,当 pointerdown 事件发生在外部或焦点移出时。可以阻止。
pointerDownOutside[event: PointerDownOutsideEvent]pointerdown 事件发生在 DismissableLayer 外部时调用的事件处理程序。可以阻止。

数据属性

属性
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"

CSS 变量

变量描述
--reka-context-menu-content-transform-origin从内容和箭头位置/偏移量计算的 transform-origin
--reka-context-menu-content-available-width触发器和边界边缘之间剩余的宽度
--reka-context-menu-content-available-height触发器和边界边缘之间剩余的高度
--reka-context-menu-trigger-width触发器的宽度
--reka-context-menu-trigger-height触发器的高度

Arrow

一个可选的箭头元素,与子菜单一起渲染。这可以用于帮助将触发项目与 ContextMenu.Content 视觉链接起来。必须在 ContextMenu.Content 内部渲染。

属性默认值类型描述
as'svg'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
height5number箭头的像素高度。
roundedboolean当为 true 时,渲染圆角版本的箭头。不适用于 as/asChild
width10number箭头的像素宽度。

Item

包含上下文菜单项目的组件。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
disabledboolean当为 true 时,阻止用户与项目交互。
textValuestring用于类型提前的可选文本。默认情况下,类型提前行为将使用项目的 .textContent。当内容复杂或内部有非文本内容时使用。

触发事件 (Emit)

事件名称Payload描述
select[event: Event]当用户选择项目(通过鼠标或键盘)时调用的事件处理程序。在此处理程序中调用 event.preventDefault 将阻止在选择该项目时菜单关闭。

数据属性

属性
[data-highlighted]高亮时存在
[data-disabled]禁用时存在

Group

用于分组多个 ContextMenu.Items

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南

Label

用于渲染标签。它不能使用箭头键聚焦。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南

CheckboxItem

可以像复选框一样控制和渲染的项目。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
disabledboolean当为 true 时,阻止用户与项目交互。
modelValuefalse | true | 'indeterminate'受控的勾选状态。可以作为 v-model 使用。
textValuestring用于类型提前的可选文本。默认情况下,类型提前行为将使用项目的 .textContent。当内容复杂或内部有非文本内容时使用。

触发事件 (Emit)

事件名称Payload描述
select[event: Event]当用户选择项目(通过鼠标或键盘)时调用的事件处理程序。在此处理程序中调用 event.preventDefault 将阻止在选择该项目时菜单关闭。
update:modelValue[payload: boolean]当值改变时调用的事件处理程序。

数据属性

属性
[data-state]"checked" | "unchecked" | "indeterminate"
[data-highlighted]高亮时存在
[data-disabled]禁用时存在

RadioGroup

用于分组多个 ContextMenu.RadioItems

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
modelValuestring组中选中项目的值。

触发事件 (Emit)

事件名称Payload描述
update:modelValue[payload: string]当值改变时调用的事件处理程序。

RadioItem

可以像单选框一样控制和渲染的项目。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
disabledboolean当为 true 时,阻止用户与项目交互。
textValuestring用于类型提前的可选文本。默认情况下,类型提前行为将使用项目的 .textContent。当内容复杂或内部有非文本内容时使用。
value*string项目的唯一值。

触发事件 (Emit)

事件名称Payload描述
select[event: Event]当用户选择项目(通过鼠标或键盘)时调用的事件处理程序。在此处理程序中调用 event.preventDefault 将阻止在选择该项目时菜单关闭。

数据属性

属性
[data-state]"checked" | "unchecked" | "indeterminate"
[data-highlighted]高亮时存在
[data-disabled]禁用时存在

ItemIndicator

当父级 ContextMenu.CheckboxItemContextMenu.RadioItem 被勾选时渲染。您可以直接设置此元素的样式,也可以将其用作放置图标的包装器,或两者兼而有之。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
forceMountboolean当需要更多控制时,用于强制挂载。在与 Vue 动画库控制动画时很有用。

数据属性

属性
[data-state]"checked" | "unchecked" | "indeterminate"

Separator

用于在上下文菜单中视觉上分隔项目。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南

Sub

包含子菜单的所有部分。

属性默认值类型描述
defaultOpenboolean子菜单首次渲染时的打开状态。当您不需要控制其打开状态时使用。
openboolean菜单的受控打开状态。可以作为 v-model:open 使用。

触发事件 (Emit)

事件名称Payload描述
update:open[payload: boolean]子菜单打开状态改变时调用的事件处理程序。

默认插槽

插槽参数Payload描述
openboolean当前打开状态

SubTrigger

打开子菜单的项目。必须在 ContextMenu.Sub 内部渲染。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
disabledboolean当为 true 时,阻止用户与项目交互。
textValuestring用于类型提前的可选文本。默认情况下,类型提前行为将使用项目的 .textContent。当内容复杂或内部有非文本内容时使用。

数据属性

属性
[data-state]"open" | "closed"
[data-highlighted]高亮时存在
[data-disabled]禁用时存在

SubContent

当子菜单打开时弹出的组件。必须在 ContextMenu.Sub 内部渲染。

属性默认值类型描述
alignFlipboolean当与边界发生碰撞时翻转对齐方式。仅在 prioritizePosition 为 true 时可能发生。
alignOffsetnumberstartend 对齐选项的像素偏移量。
arrowPaddingnumber箭头与内容边缘之间的填充。如果您的内容有 border-radius,这将防止它溢出角。
as'div'AsTag | Component此组件应渲染为的元素或组件。可以通过 asChild 覆盖。
asChildfalseboolean将默认渲染的元素更改为作为子元素传递的元素,合并它们的 props 和行为。有关详细信息,请阅读我们的组合指南
avoidCollisionsboolean当为 true 时,覆盖侧边和对齐偏好以防止与边界边缘碰撞。
collisionBoundaryElement | (Element | null)[] | null用作碰撞边界的元素。默认情况下是视口,但您可以提供额外的元素以包含在此检查中。
collisionPaddingnumber | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>碰撞检测应发生的边界边缘的像素距离。接受一个数字(所有边相同),或一个部分填充对象,例如:{ top: 20, left: 20 }
disableUpdateOnLayoutShiftboolean是否在布局偏移时禁用内容更新位置。
forceMountboolean当需要更多控制时,用于强制挂载。在与 Vue 动画库控制动画时很有用。
hideWhenDetachedboolean当触发器完全被遮挡时是否隐藏内容。
loopboolean当为 true 时,键盘导航将从最后一个项目循环到第一个,反之亦然。
positionStrategy'fixed' | 'absolute'要使用的 CSS position 属性类型。
prioritizePositionboolean强制内容在视口内定位。可能会与参考元素重叠,这可能不是期望的。
referenceReferenceElement将作为浮动元素定位参考的自定义元素或虚拟元素。如果提供,它将替换默认锚点元素。
sideOffsetnumber与触发器的像素距离。
sticky'partial' | 'always'对齐轴上的粘性行为。partial 将使内容保持在边界内,只要触发器至少部分在边界内,而 always 将无论如何都使内容保持在边界内。
updatePositionStrategy'always' | 'optimized'在每个动画帧上更新浮动元素位置的策略。

触发事件 (Emit)

事件名称Payload描述
closeAutoFocus[event: Event]关闭时自动聚焦时调用的事件处理程序。可以阻止。
entryFocus[event: Event]容器被聚焦时调用的事件处理程序。可以阻止。
escapeKeyDown[event: KeyboardEvent]Escape 键按下时调用的事件处理程序。可以阻止。
focusOutside[event: FocusOutsideEvent]焦点移出 DismissableLayer 时调用的事件处理程序。可以阻止。
interactOutside[event: PointerDownOutsideEvent | FocusOutsideEvent]DismissableLayer 外部发生交互时调用的事件处理程序。具体来说,当 pointerdown 事件发生在外部或焦点移出时。可以阻止。
openAutoFocus[event: Event]打开时自动聚焦时调用的事件处理程序。可以阻止。
pointerDownOutside[event: PointerDownOutsideEvent]pointerdown 事件发生在 DismissableLayer 外部时调用的事件处理程序。可以阻止。

数据属性

属性
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"

CSS 变量

变量描述
--reka-context-menu-content-transform-origin从内容和箭头位置/偏移量计算的 transform-origin
--reka-context-menu-content-available-width触发器和边界边缘之间剩余的宽度
--reka-context-menu-content-available-height触发器和边界边缘之间剩余的高度
--reka-context-menu-trigger-width触发器的宽度
--reka-context-menu-trigger-height触发器的高度

示例

使用子菜单

您可以结合使用 ContextMenuSub 及其部分来创建子菜单。

<script setup lang="ts">
  import {
    ContextMenuContent,
    ContextMenuItem,
    ContextMenuLabel,
    ContextMenuPortal,
    ContextMenuRoot,
    ContextMenuSeparator,
    ContextMenuSub,
    ContextMenuSubContent,
    ContextMenuSubTrigger,
    ContextMenuTrigger,
  } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuSeparator />
        <ContextMenuSub>
          <ContextMenuSubTrigger>Sub menu →</ContextMenuSubTrigger>
          <ContextMenuPortal>
            <ContextMenuSubContent>
              <ContextMenuItem>Sub menu item</ContextMenuItem>
              <ContextMenuItem>Sub menu item</ContextMenuItem>
              <ContextMenuArrow />
            </ContextMenuSubContent>
          </ContextMenuPortal>
        </ContextMenuSub>
        <ContextMenuSeparator />
        <ContextMenuItem></ContextMenuItem>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

使用禁用项

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

<script setup lang="ts">
  import { ContextMenuContent, ContextMenuItem, ContextMenuPortal, ContextMenuRoot, ContextMenuTrigger } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuItem
          class="ContextMenuItem"
          disabled
        >
        </ContextMenuItem>
        <ContextMenuItem class="ContextMenuItem">
        </ContextMenuItem>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>
styles.css
.ContextMenuItem[data-disabled] {
  color: gainsboro;
}

使用分隔符

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

<script setup lang="ts">
  import {
    ContextMenuContent,
    ContextMenuItem,
    ContextMenuPortal,
    ContextMenuRoot,
    ContextMenuSeparator,
    ContextMenuTrigger,
  } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuSeparator />
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuSeparator />
        <ContextMenuItem></ContextMenuItem>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

使用标签

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

<script setup lang="ts">
  import {
    ContextMenuContent,
    ContextMenuItem,
    ContextMenuLabel,
    ContextMenuPortal,
    ContextMenuRoot,
    ContextMenuTrigger,
  } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuLabel>Label</ContextMenuLabel>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuItem></ContextMenuItem>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

使用复选框项

使用 CheckboxItem 部分添加一个可勾选的项目。

<script setup lang="ts">
  import { Icon } from '@iconify/vue'
  import {
    ContextMenuCheckboxItem,
    ContextMenuContent,
    ContextMenuItem,
    ContextMenuItemIndicator,
    ContextMenuPortal,
    ContextMenuRoot,
    ContextMenuSeparator,
    ContextMenuTrigger,
  } from 'reka-ui'

  const checked = ref(true)
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuItem></ContextMenuItem>
        <ContextMenuSeparator />
        <ContextMenuCheckboxItem v-model="checked">
          <ContextMenuItemIndicator>
            <Icon icon="radix-icons:check" />
          </ContextMenuItemIndicator>
          Checkbox item
        </ContextMenuCheckboxItem>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

带单选框项

使用 RadioGroupRadioItem 部分添加一个可在其他项目之间选择的项目。

<script setup lang="ts">
  import { Icon } from '@iconify/vue'
  import {
    ContextMenuCheckboxItem,
    ContextMenuContent,
    ContextMenuItem,
    ContextMenuItemIndicator,
    ContextMenuPortal,
    ContextMenuRadioGroup,
    ContextMenuRadioItem,
    ContextMenuRoot,
    ContextMenuSeparator,
    ContextMenuTrigger,
  } from 'reka-ui'

  const color = ref('blue')
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuRadioGroup v-model="color">
          <ContextMenuRadioItem value="red">
            <ContextMenuItemIndicator>
              <Icon icon="radix-icons:check" />
            </ContextMenuItemIndicator>
            Red
          </ContextMenuRadioItem>
          <ContextMenuRadioItem value="blue">
            <ContextMenuItemIndicator>
              <Icon icon="radix-icons:check" />
            </ContextMenuItemIndicator>
            Blue
          </ContextMenuRadioItem>
          <ContextMenuRadioItem value="green">
            <ContextMenuItemIndicator>
              <Icon icon="radix-icons:check" />
            </ContextMenuItemIndicator>
            Green
          </ContextMenuRadioItem>
        </ContextMenuRadioGroup>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

带复杂项

您可以在 Item 部分中添加额外的装饰元素,例如图片。

<script setup lang="ts">
  import { ContextMenuContent, ContextMenuItem, ContextMenuPortal, ContextMenuRoot, ContextMenuTrigger } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent>
        <ContextMenuItem>
          <img src="">
          Adolfo Hess
        </ContextMenuItem>
        <ContextMenuItem>
          <img src="">
          Miyah Myles
        </ContextMenuItem>
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>

限制内容/子内容大小

您可能希望限制内容(或子内容)的宽度,使其与触发器(或子触发器)的宽度匹配。您可能还希望限制其高度不超过视口。

我们暴露了几个 CSS 自定义属性,例如 --reka-context-menu-trigger-width--reka-context-menu-content-available-height 来支持这一点。使用它们来限制内容尺寸。

<script setup lang="ts">
  import { ContextMenuContent, ContextMenuItem, ContextMenuPortal, ContextMenuRoot, ContextMenuTrigger } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent class="ContextMenuContent">
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>
styles.css
.ContextMenuContent {
  width: var(--reka-context-menu-trigger-width);
  max-height: var(--reka-context-menu-content-available-height);
}

感知源动画

我们暴露了一个 CSS 自定义属性 --reka-context-menu-content-transform-origin。使用它来根据 sidesideOffsetalignalignOffset 和任何碰撞从计算出的原点动画内容。

<script setup lang="ts">
  import { ContextMenuContent, ContextMenuPortal, ContextMenuRoot, ContextMenuTrigger } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent class="ContextMenuContent">
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>
styles.css
.ContextMenuContent {
  transform-origin: var(--reka-context-menu-content-transform-origin);
  animation: scaleIn 0.5s ease-out;
}

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

感知碰撞动画

我们暴露了 data-sidedata-align 属性。它们的值将在运行时改变以反映碰撞。使用它们来创建感知碰撞和方向的动画。

<script setup lang="ts">
  import { ContextMenuContent, ContextMenuPortal, ContextMenuRoot, ContextMenuTrigger } from 'reka-ui'
</script>

<template>
  <ContextMenuRoot>
    <ContextMenuTrigger></ContextMenuTrigger>
    <ContextMenuPortal>
      <ContextMenuContent class="ContextMenuContent">
      </ContextMenuContent>
    </ContextMenuPortal>
  </ContextMenuRoot>
</template>
styles.css
.ContextMenuContent {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

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

.ContextMenuContent[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);
  }
}

可访问性

使用 漫游 tabindex 来管理菜单项之间的焦点移动。

键盘交互

按键描述
Space激活聚焦的项目。
Enter激活聚焦的项目。
ArrowDown将焦点移至下一个项目。
ArrowUp将焦点移至上一个项目。
ArrowRight ArrowLeft当焦点在 ContextMenu.SubTrigger 上时,根据阅读方向打开或关闭子菜单。
Esc关闭上下文菜单。