Basic Popover
A click-triggered panel anchored to its button, with Escape and outside-click dismiss.
6 个框架中级
A menu whose last item opens a submenu - flying out on desktop, stacking at 320px.
<div class="relative inline-block">
<button type="button" aria-haspopup="menu" aria-expanded="true" aria-controls="pnest-menu" class="rounded-lg border border-gray-300 bg-white px-3.5 py-2 text-sm font-semibold text-gray-700 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:focus-visible:ring-blue-400 dark:focus-visible:ring-offset-gray-900">
Actions
</button>
<ul id="pnest-menu" role="menu" aria-label="Actions" class="absolute left-0 top-[calc(100%+0.375rem)] z-20 min-w-48 max-w-[calc(100vw-2rem)] rounded-xl border border-gray-200 bg-white p-1 shadow-lg dark:border-gray-700 dark:bg-gray-900">
<li role="none"><button type="button" role="menuitem" class="block w-full rounded-md px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus-visible:bg-gray-100 focus-visible:text-gray-900 focus-visible:outline-none dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:focus-visible:bg-gray-800 dark:focus-visible:text-gray-100">Rename</button></li>
<li role="none"><button type="button" role="menuitem" class="block w-full rounded-md px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus-visible:bg-gray-100 focus-visible:text-gray-900 focus-visible:outline-none dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:focus-visible:bg-gray-800 dark:focus-visible:text-gray-100">Duplicate</button></li>
<li role="none" class="relative">
<!-- Submenu trigger: aria-haspopup="menu" + aria-expanded describe the
branch. ArrowRight/Enter open it, ArrowLeft/Escape step back. -->
<button type="button" role="menuitem" aria-haspopup="menu" aria-expanded="true" aria-controls="pnest-sub" class="flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus-visible:bg-gray-100 focus-visible:text-gray-900 focus-visible:outline-none dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:focus-visible:bg-gray-800 dark:focus-visible:text-gray-100">
Move to…
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="h-4 w-4" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="m9 6 6 6-6 6" /></svg>
</button>
<!-- Flies out on sm+, stacks inline at 320px so it never leaves the viewport. -->
<ul id="pnest-sub" role="menu" aria-label="Move to" class="mt-1 w-full rounded-lg border border-gray-200 bg-white p-1 shadow-lg sm:absolute sm:left-full sm:top-0 sm:ml-1 sm:mt-0 sm:w-44 dark:border-gray-700 dark:bg-gray-900">
<li role="none"><button type="button" role="menuitem" class="block w-full rounded-md px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus-visible:bg-gray-100 focus-visible:text-gray-900 focus-visible:outline-none dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:focus-visible:bg-gray-800 dark:focus-visible:text-gray-100">Inbox</button></li>
<li role="none"><button type="button" role="menuitem" class="block w-full rounded-md px-3 py-2 text-left text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 focus-visible:bg-gray-100 focus-visible:text-gray-900 focus-visible:outline-none dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:focus-visible:bg-gray-800 dark:focus-visible:text-gray-100">Archive</button></li>
</ul>
</li>
</ul>
</div>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
label必填 | string | - | 加载时朗读的无障碍标签。 |
items必填 | readonly string[] | - | 要渲染的项目数组。 |
moreLabel必填 | string | - | More label |
moreItems必填 | readonly string[] | - | More items |
onSelect | (item: string) => void | - | 用户选择菜单项时触发,参数为所选项。 |
A `role="menu"` whose last item opens a nested `role="menu"`: `aria-haspopup="menu"` and `aria-expanded` describe the branch, ArrowRight/Enter open it, ArrowLeft/Escape step back one layer at a time. The submenu flies out to the right on `sm+` but stacks inline at 320px, so it never leaves a narrow viewport - the single hardest part of a real flyout. Leaf clicks close the whole tree and return focus to the trigger.