一个非模态 React 浮层,锚定在触发元素旁,采用 Liquid Glass 面板。
Popover 内部渲染触发元素、Portal、定位器、玻璃弹窗、指向缺口、标题、描述、可选正文以及可选操作区。指向缺口会自动跟随弹窗实际所在的方位;设置 arrow={false} 可以隐藏它。
与 Dialog 和 Drawer 不同,Popover 默认是非模态的:不会锁定焦点,页面仍可滚动,点击外部或按 Esc 会关闭。适合紧凑的设置面板、上下文操作和筛选条件。
trigger 接收单个元素,并且该元素需要把 props 和 ref 透传到根元素,例如内置的 Button。组件会自动为触发元素添加 aria-haspopup="dialog" 和 aria-expanded,点击即可切换浮层。此示例为非受控用法。
open 与 onOpenChange 控制显示状态。footer 中的按钮不会自动关闭浮层,需要像示例一样自行更新 open。
No release published.
side、align、sideOffset 和 alignOffset 控制弹窗定位。空间不足时,弹窗会自动翻转或平移。
align、alignOffset 与 collisionPadding 会在确定首选方向后进一步微调位置。设置 arrow={false} 可以让浮层不带箭头、紧贴触发器显示。
Popover 会为触发器添加 aria-haspopup="dialog" 与 aria-expanded,并渲染由 title 命名、由 description 描述的浮层。
默认是非模态的:焦点不会被限制,页面仍可滚动,Escape 或点击外部会关闭。浮层会修改设置时,请提供可见的关闭或完成操作。当前封装无法通过 modal 启用焦点陷阱:Base UI 只有在渲染了 Popover.Close 时才会启用,而组件没有渲染该部分。modal={true} 仍会锁定页面滚动并阻止外部交互。焦点规则见可访问性指南。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
trigger | ReactElement | — | 打开浮层的元素,必填;需要透传 props 和 ref。 |
title | ReactNode | — | 浮层标题,必填。 |
description | ReactNode | — | 标题下方的说明文字。 |
children | ReactNode | — | 描述与操作区之间的正文内容。 |
footer | ReactNode | — | 底部操作区,可放置任意数量的控件。 |
arrow | boolean | true | 是否渲染指向缺口。 |
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" | 优先放置在触发元素的哪一侧。 |
align | "start" | "center" | "end" | "center" | 相对于触发元素的对齐方式。 |
sideOffset | number | OffsetFunction | 10 | 触发元素与弹窗之间的距离(像素)。 |
alignOffset | number | OffsetFunction | 0 | 沿对齐轴的偏移量(像素)。 |
collisionPadding | Padding | 每侧 5px | 弹窗与碰撞边界之间保留的空间。 |
open | boolean | — | 受控的打开状态。 |
defaultOpen | boolean | false | 非受控时的初始打开状态。 |
onOpenChange | (open: boolean, details) => void | — | 浮层打开或关闭时调用。 |
onOpenChangeComplete | (open: boolean) => void | — | 打开或关闭动画结束后调用。 |
modal | boolean | "trap-focus" | false | true 会锁定页面滚动并阻止外部交互;"trap-focus" 不锁定滚动,也保留外部交互。组件未渲染 Popover.Close,因此两者都不会启用焦点陷阱。 |
actionsRef | RefObject<Actions | null> | — | 命令式的 close 与 unmount 操作。 |
handle | PopoverHandle | — | 将浮层与外部触发器关联。 |
triggerId | string | null | — | 与浮层关联的触发器 ID。 |
defaultTriggerId | string | null | — | 初始打开时使用的触发器 ID。 |
className | string | — | 合并到弹窗的 Tailwind 类名。 |
style | CSSProperties | — | 内联样式,合并到与 className 相同的元素。 |
ui | { positioner?: ClassValue; popup?: ClassValue; glass?: ClassValue; overlay?: ClassValue; arrow?: ClassValue; content?: ClassValue; title?: ClassValue; description?: ClassValue; body?: ClassValue; footer?: ClassValue } | — | 按 data-slot 组织的内部槽位类名。 |
| 属性 | 说明 |
|---|---|
data-open | 弹窗打开时存在。 |
data-closed | 弹窗关闭时存在。 |
data-starting-style | 弹窗开始进入动画时存在。 |
data-ending-style | 弹窗正在退出动画时存在。 |
data-side | 表示解析后的方位(top、bottom、left、right、inline-start 或 inline-end)。 |
data-align | 表示解析后的对齐方式(start、center 或 end)。 |
data-instant | 动画需要跳过时存在(click、dismiss、focus 或 trigger-change)。 |
data-anchor-hidden | 锚点隐藏时存在。 |
data-uncentered | 指向缺口未居中时存在。 |
data-popup-open | 弹窗打开时存在于触发元素上。 |
data-pressed | 触发元素被按下时存在。 |
data-slot | 标记内部部件(positioner、popup、glass、overlay、arrow、content、title、description、body、footer),用于样式选择。 |
组件使用共享玻璃材质。可以在父级调整 --ui-glass-* token,用 className 控制布局,并通过 ui 按 data-slot 调整内部槽位。组件级数值位于 src/theme/popover.ts。Token 分层与预设见主题指南。