Admin 元件

Dropdown Menu

參考API
點按 trigger 後彈出的選項列表;含鍵盤導航。

安裝

Terminal
pnpm dlx shadcn-vue add @admin/dropdown-menu
import {  AdminDropdownMenu,  AdminDropdownMenuCheckboxItem,  AdminDropdownMenuContent,  AdminDropdownMenuGroup,  AdminDropdownMenuItem,  AdminDropdownMenuLabel,  AdminDropdownMenuRadioGroup,  AdminDropdownMenuRadioItem,  AdminDropdownMenuSeparator,  AdminDropdownMenuShortcut,  AdminDropdownMenuSub,  AdminDropdownMenuSubContent,  AdminDropdownMenuSubTrigger,  AdminDropdownMenuTrigger,} from '@/components/admin/dropdown-menu'

用法

點 trigger 顯示 content;items 由鍵盤 ArrowUp / ArrowDown 切換 highlight、Enter 觸發 select、Escape 關閉。

<script setup lang="ts">import { AdminButton } from '@/components/admin/button'import {  AdminDropdownMenu,  AdminDropdownMenuContent,  AdminDropdownMenuItem,  AdminDropdownMenuLabel,  AdminDropdownMenuSeparator,  AdminDropdownMenuTrigger} from '@/components/admin/dropdown-menu'</script>​<template>  <admin-dropdown-menu>    <admin-dropdown-menu-trigger as-child>      <admin-button variant="outline">開啟選單</admin-button>    </admin-dropdown-menu-trigger>    <admin-dropdown-menu-content align="start">      <admin-dropdown-menu-label>我的帳號</admin-dropdown-menu-label>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-item>個人資料</admin-dropdown-menu-item>      <admin-dropdown-menu-item>帳號設定</admin-dropdown-menu-item>      <admin-dropdown-menu-item disabled>付費方案(停用)</admin-dropdown-menu-item>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-item>登出</admin-dropdown-menu-item>    </admin-dropdown-menu-content>  </admin-dropdown-menu></template>

場景

操作選單

行內 action menu,含 disabled item 與 separator 分組;常用於列表 row 右側「⋯」按鈕。

<script setup lang="ts">import { AdminButton } from '@/components/admin/button'import {  AdminDropdownMenu,  AdminDropdownMenuContent,  AdminDropdownMenuItem,  AdminDropdownMenuSeparator,  AdminDropdownMenuTrigger} from '@/components/admin/dropdown-menu'​function onAction(name: string) {  // eslint-disable-next-line no-console  console.log('action:', name)}</script>​<template>  <admin-dropdown-menu>    <admin-dropdown-menu-trigger as-child>      <admin-button aria-label="更多操作" size="small" variant="ghost">⋯</admin-button>    </admin-dropdown-menu-trigger>    <admin-dropdown-menu-content align="end">      <admin-dropdown-menu-item @select="onAction('edit')">編輯</admin-dropdown-menu-item>      <admin-dropdown-menu-item @select="onAction('duplicate')">複製</admin-dropdown-menu-item>      <admin-dropdown-menu-item @select="onAction('move')">移動到...</admin-dropdown-menu-item>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-item disabled>歸檔(停用)</admin-dropdown-menu-item>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-item @select="onAction('delete')">刪除</admin-dropdown-menu-item>    </admin-dropdown-menu-content>  </admin-dropdown-menu></template>

進階選單

checkbox item(多選)、radio group(單選)、巢狀 sub-menu、快捷鍵提示。

<script setup lang="ts">import type { AcceptableValue } from 'reka-ui'import { ref } from 'vue'import { AdminButton } from '@/components/admin/button'import {  AdminDropdownMenu,  AdminDropdownMenuCheckboxItem,  AdminDropdownMenuContent,  AdminDropdownMenuGroup,  AdminDropdownMenuItem,  AdminDropdownMenuLabel,  AdminDropdownMenuRadioGroup,  AdminDropdownMenuRadioItem,  AdminDropdownMenuSeparator,  AdminDropdownMenuShortcut,  AdminDropdownMenuSub,  AdminDropdownMenuSubContent,  AdminDropdownMenuSubTrigger,  AdminDropdownMenuTrigger} from '@/components/admin/dropdown-menu'​const showStatusBar = ref(true)const showActivityBar = ref(false)const position = ref<AcceptableValue>('bottom')</script>​<template>  <admin-dropdown-menu>    <admin-dropdown-menu-trigger as-child>      <admin-button variant="outline">檢視選項</admin-button>    </admin-dropdown-menu-trigger>    <admin-dropdown-menu-content align="start" class="w-56">      <admin-dropdown-menu-label>外觀</admin-dropdown-menu-label>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-checkbox-item v-model="showStatusBar">        狀態列      </admin-dropdown-menu-checkbox-item>      <admin-dropdown-menu-checkbox-item v-model="showActivityBar">        活動列      </admin-dropdown-menu-checkbox-item>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-label>面板位置</admin-dropdown-menu-label>      <admin-dropdown-menu-radio-group v-model="position">        <admin-dropdown-menu-radio-item value="top">上方</admin-dropdown-menu-radio-item>        <admin-dropdown-menu-radio-item value="bottom">下方</admin-dropdown-menu-radio-item>        <admin-dropdown-menu-radio-item value="right">右側</admin-dropdown-menu-radio-item>      </admin-dropdown-menu-radio-group>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-group>        <admin-dropdown-menu-item>          新增檔案          <admin-dropdown-menu-shortcut>⌘N</admin-dropdown-menu-shortcut>        </admin-dropdown-menu-item>        <admin-dropdown-menu-sub>          <admin-dropdown-menu-sub-trigger>更多工具</admin-dropdown-menu-sub-trigger>          <admin-dropdown-menu-sub-content>            <admin-dropdown-menu-item>移動到…</admin-dropdown-menu-item>            <admin-dropdown-menu-item>複製連結</admin-dropdown-menu-item>            <admin-dropdown-menu-separator />            <admin-dropdown-menu-sub>              <admin-dropdown-menu-sub-trigger>匯出為</admin-dropdown-menu-sub-trigger>              <admin-dropdown-menu-sub-content>                <admin-dropdown-menu-item>PDF</admin-dropdown-menu-item>                <admin-dropdown-menu-item>PNG</admin-dropdown-menu-item>              </admin-dropdown-menu-sub-content>            </admin-dropdown-menu-sub>          </admin-dropdown-menu-sub-content>        </admin-dropdown-menu-sub>      </admin-dropdown-menu-group>    </admin-dropdown-menu-content>  </admin-dropdown-menu></template>

鍵盤導航

快捷鍵行為
ArrowDown / ArrowUp移動 highlight 到下一個 / 上一個 item
Enter / Space觸發 highlighted item 的 select event 並關閉 menu
Escape關閉 menu,focus 回 trigger
Tab關閉 menu,focus 移到下一個 tabbable 元素
Home / End跳到第一個 / 最後一個 item
ArrowRight在 sub-trigger 上展開子選單並 focus 第一個 item(RTL 相反)
ArrowLeft收合子選單,focus 回 sub-trigger(RTL 相反)
任意可印字元type-ahead 跳到 textValue 開頭符合的 item

行為由 reka-ui DropdownMenu primitive 提供,本元件薄包一層樣式。

與其他元件的差別

元件適用情境
admin-dropdown-menu觸發後彈出的「選項列表」,含鍵盤導航;典型用例:navigation menu、action menu、heading dropdown
admin-popover任意 內容浮層(不限選項列表);沒有 roving tabindex / arrow key 導航
admin-select表單欄位用的 單選,會把選定值寫回 <input>

API 參考

組成

<template>  <admin-dropdown-menu>    <admin-dropdown-menu-trigger>開啟選單</admin-dropdown-menu-trigger>    <admin-dropdown-menu-content>      <admin-dropdown-menu-label>群組標題</admin-dropdown-menu-label>      <admin-dropdown-menu-separator />      <admin-dropdown-menu-item>        選項一        <admin-dropdown-menu-shortcut>⌘K</admin-dropdown-menu-shortcut>      </admin-dropdown-menu-item>      <admin-dropdown-menu-checkbox-item v-model="checked">可勾選項</admin-dropdown-menu-checkbox-item>      <admin-dropdown-menu-radio-group v-model="value">        <admin-dropdown-menu-radio-item value="a">單選 A</admin-dropdown-menu-radio-item>        <admin-dropdown-menu-radio-item value="b">單選 B</admin-dropdown-menu-radio-item>      </admin-dropdown-menu-radio-group>      <admin-dropdown-menu-sub>        <admin-dropdown-menu-sub-trigger>更多</admin-dropdown-menu-sub-trigger>        <admin-dropdown-menu-sub-content>          <admin-dropdown-menu-item>子選項</admin-dropdown-menu-item>        </admin-dropdown-menu-sub-content>      </admin-dropdown-menu-sub>    </admin-dropdown-menu-content>  </admin-dropdown-menu></template>

admin-dropdown-menu

Props

名稱型別預設值說明
defaultOpenboolean | undefined—The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state.
openboolean | undefined—The controlled open state of the menu. Can be used as `v-model:open`.
dirDirection$4 | undefined—The reading direction of the combobox when applicable. If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode.
modalboolean | undefined—The modality of the dropdown menu. When set to `true`, interaction with outside elements will be disabled and only menu content will be visible to screen readers.
classunknown——

Events

名稱Payload說明
update:openboolean—

Slots

名稱Bindings說明
default{ open: boolean; }—

admin-dropdown-menu-trigger

Props

名稱型別預設值說明
disabledboolean | undefined—When `true`, prevents the user from interacting with item
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-content

Props

名稱型別預設值說明
forceMountboolean | undefined—Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
loopboolean | undefinedfalseWhen `true`, keyboard navigation will loop from last item to first, and vice versa.
align"start" | "end" | "center" | undefined"center"The preferred alignment against the trigger. May change when collisions occur.
sideOffsetnumber | undefined4The distance in pixels from the trigger.
memoDependenciesunknown[] | undefined—Reactive dependencies that should invalidate the memoized content subtree.
side"top" | "right" | "bottom" | "left" | undefined"bottom"The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
sideFlipboolean | undefinedtrueFlip to the opposite side when colliding with boundary.
alignOffsetnumber | undefined0An offset in pixels from the `start` or `end` alignment options.
alignFlipboolean | undefinedtrueFlip alignment when colliding with boundary. May only occur when `prioritizePosition` is true.
avoidCollisionsboolean | undefinedtrueWhen `true`, overrides the side and align preferences to prevent collisions with boundary edges.
collisionBoundaryElement | (Element | null)[] | null | undefined[]The element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check.
collisionPaddingnumber | Partial<Record<"top" | "right" | "bottom" | "left", number>> | undefined0The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }.
arrowPaddingnumber | undefined0The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners.
hideShiftedArrowboolean | undefinedtrueWhen `true`, hides the arrow when it cannot be centered to the reference element.
sticky"partial" | "always" | undefined"partial"The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless.
hideWhenDetachedboolean | undefinedfalseWhether to hide the content when the trigger becomes fully occluded.
positionStrategy"fixed" | "absolute" | undefined—The type of CSS position property to use.
updatePositionStrategy"always" | "optimized" | undefined'optimized'Strategy to update the position of the floating element on every animation frame.
disableUpdateOnLayoutShiftboolean | undefinedfalseWhether to disable the update position for the content when the layout shifted.
prioritizePositionboolean | undefinedfalseForce content to be position within the viewport. Might overlap the reference element, which may not be desired.
referenceReferenceElement | undefined—The custom element or virtual element that will be set as the reference to position the floating element. If provided, it will replace the default anchor element.
classClassValue——
tostring | HTMLElement | undefined——

Events

名稱Payload說明
escapeKeyDownKeyboardEvent—
pointerDownOutsidePointerDownOutsideEvent—
focusOutsideFocusOutsideEvent—
interactOutsidePointerDownOutsideEvent | FocusOutsideEvent—
closeAutoFocusEvent—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-item

Props

名稱型別預設值說明
disabledboolean | undefined—When `true`, prevents the user from interacting with the item.
textValuestring | undefined—Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——
insetboolean | undefinedfalse—

Events

名稱Payload說明
selectEvent—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-separator

Props

名稱型別預設值說明
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——

admin-dropdown-menu-label

Props

名稱型別預設值說明
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——
insetboolean | undefinedfalse—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-group

Props

名稱型別預設值說明
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classunknown——

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-checkbox-item

Props

名稱型別預設值說明
modelValueCheckedState | undefined—The controlled checked state of the item. Can be used as `v-model`.
disabledboolean | undefined—When `true`, prevents the user from interacting with the item.
textValuestring | undefined—Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——

Events

名稱Payload說明
selectEvent—
update:modelValueboolean—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-radio-group

Props

名稱型別預設值說明
modelValueAcceptableValue | undefined—The value of the selected item in the group.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——

Events

名稱Payload說明
update:modelValueAcceptableValue—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-radio-item

Props

名稱型別預設值說明
value*AcceptableValue—The unique value of the item.
disabledboolean | undefined—When `true`, prevents the user from interacting with the item.
textValuestring | undefined—Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——

* 代表必填

Events

名稱Payload說明
selectEvent—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-sub

Props

名稱型別預設值說明
defaultOpenboolean | undefined—The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state.
openboolean | undefined—The controlled open state of the menu. Can be used as `v-model:open`.
classunknown——

Events

名稱Payload說明
update:openboolean—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-sub-trigger

Props

名稱型別預設值說明
disabledboolean | undefined—When `true`, prevents the user from interacting with the item.
textValuestring | undefined—Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. Use this when the content is complex, or you have non-textual content inside.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
classClassValue——
insetboolean | undefinedfalse—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-sub-content

Props

名稱型別預設值說明
forceMountboolean | undefined—Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries.
asglobalThis.Component | AsTag | undefined"div"The element or component this component should render as. Can be overwritten by `asChild`.
asChildboolean | undefined—Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
loopboolean | undefinedfalseWhen `true`, keyboard navigation will loop from last item to first, and vice versa.
sideOffsetnumber | undefined0The distance in pixels from the trigger.
memoDependenciesunknown[] | undefined—Reactive dependencies that should invalidate the memoized content subtree.
sideFlipboolean | undefinedtrueFlip to the opposite side when colliding with boundary.
alignOffsetnumber | undefined0An offset in pixels from the `start` or `end` alignment options.
alignFlipboolean | undefinedtrueFlip alignment when colliding with boundary. May only occur when `prioritizePosition` is true.
avoidCollisionsboolean | undefinedtrueWhen `true`, overrides the side and align preferences to prevent collisions with boundary edges.
collisionBoundaryElement | (Element | null)[] | null | undefined[]The element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check.
collisionPaddingnumber | Partial<Record<"top" | "right" | "bottom" | "left", number>> | undefined0The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }.
arrowPaddingnumber | undefined0The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners.
hideShiftedArrowboolean | undefinedtrueWhen `true`, hides the arrow when it cannot be centered to the reference element.
sticky"partial" | "always" | undefined"partial"The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless.
hideWhenDetachedboolean | undefinedfalseWhether to hide the content when the trigger becomes fully occluded.
positionStrategy"fixed" | "absolute" | undefined—The type of CSS position property to use.
updatePositionStrategy"always" | "optimized" | undefined'optimized'Strategy to update the position of the floating element on every animation frame.
disableUpdateOnLayoutShiftboolean | undefinedfalseWhether to disable the update position for the content when the layout shifted.
prioritizePositionboolean | undefinedfalseForce content to be position within the viewport. Might overlap the reference element, which may not be desired.
referenceReferenceElement | undefined—The custom element or virtual element that will be set as the reference to position the floating element. If provided, it will replace the default anchor element.
classClassValue——

Events

名稱Payload說明
escapeKeyDownKeyboardEvent—
pointerDownOutsidePointerDownOutsideEvent—
focusOutsideFocusOutsideEvent—
interactOutsidePointerDownOutsideEvent | FocusOutsideEvent—
openAutoFocusEvent—
closeAutoFocusEvent—
entryFocusEvent—

Slots

名稱Bindings說明
default{}—

admin-dropdown-menu-shortcut

Props

名稱型別預設值說明
classClassValue——

Slots

名稱Bindings說明
default{}—

更新紀錄

  • fix: 與上游同步修正 shadcn-vue 的收合點擊與浮層可用寬af0690c
  • feat: 補齊 checkbox/radio/sub-menu 子元件對齊 shadcn-vueb44972a
  • feat: 新增 admin-dropdown-menu 元件1ca9c82