Popover
Popover 从 HeroUI v2 到 v3 的迁移指南。
完整的 API 参考、样式指南与高级示例请参阅 v3 Popover 文档。本指南只关注从 HeroUI v2 的迁移。
结构变化
在 v2 中,Popover 由独立的多个组件组成:
import { Popover, PopoverTrigger, PopoverContent, Button } from "@heroui/react";
export default function App() {
return (
<Popover placement="right">
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover>
);
}在 v3 中,Popover 改为复合组件:
import { Popover, Button } from "@heroui/react";
export default function App() {
return (
<Popover>
<Button>Open</Button>
<Popover.Content>
<Popover.Dialog>
<Popover.Heading>Title</Popover.Heading>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>
);
}主要变化
1. 组件结构
v2: 独立的多个组件(Popover、PopoverTrigger、PopoverContent)
v3: 复合组件(Popover、Popover.Trigger、Popover.Content、Popover.Dialog、Popover.Heading、Popover.Arrow)
2. Prop 变更
| v2 prop | v3 位置 | 说明 |
|---|---|---|
placement | placement(在 Content 上) | 移至 Popover.Content |
offset | offset(在 Content 上) | 移至 Popover.Content |
shouldFlip | shouldFlip(在 Content 上) | 移至 Popover.Content |
isOpen / defaultOpen / onOpenChange | 同名(在根上) | 受控状态仍保留在根 Popover 上 |
showArrow | — | 改用 Popover.Arrow 子组件 |
size | — | 已移除(请改用 Tailwind CSS) |
color | — | 已移除(请改用 Tailwind CSS) |
radius | — | 已移除(请改用 Tailwind CSS) |
shadow | — | 已移除(请改用 Tailwind CSS) |
backdrop | — | 已移除 |
motionProps | — | 已移除(动画机制已不同) |
classNames | — | 改在各子组件上使用 className |
onClose | — | 改用 onOpenChange((open) => { if (!open) { ... } }) |
迁移示例
内容配置
{/* With arrow */}
<Popover showArrow>
<PopoverTrigger><Button>Open</Button></PopoverTrigger>
<PopoverContent><div>Content</div></PopoverContent>
</Popover>
{/* With placement */}
<Popover placement="top">
<PopoverTrigger><Button>Open</Button></PopoverTrigger>
<PopoverContent><div>Content</div></PopoverContent>
</Popover>
{/* With offset */}
<Popover offset={10}>
<PopoverTrigger><Button>Open</Button></PopoverTrigger>
<PopoverContent><div>Content</div></PopoverContent>
</Popover>{/* With arrow - use component */}
<Popover>
<Button>Open</Button>
<Popover.Content>
<Popover.Dialog>
<Popover.Arrow />
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>
{/* With placement - moved to Content */}
<Popover>
<Button>Open</Button>
<Popover.Content placement="top">
<Popover.Dialog>
<Popover.Arrow />
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>
{/* With offset - moved to Content */}
<Popover>
<Button>Open</Button>
<Popover.Content offset={10}>
<Popover.Dialog>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>带标题
<PopoverContent>
<div className="px-1 py-2">
<div className="text-small font-bold">Title</div>
<div className="text-tiny">Content</div>
</div>
</PopoverContent><Popover.Content>
<Popover.Dialog>
<Popover.Heading>Title</Popover.Heading>
<p className="text-muted mt-2 text-sm">Content</p>
</Popover.Dialog>
</Popover.Content>受控
import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
<Popover isOpen={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<div>Content</div>
</PopoverContent>
</Popover>import { useState } from "react";
const [isOpen, setIsOpen] = useState(false);
<Popover isOpen={isOpen} onOpenChange={setIsOpen}>
<Button>Open</Button>
<Popover.Content>
<Popover.Dialog>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>自定义触发器
<PopoverTrigger>
<CustomButton>Custom</CustomButton>
</PopoverTrigger><Popover.Trigger>
<CustomButton>Custom</CustomButton>
</Popover.Trigger>组件结构
v3 Popover 遵循以下结构:
Popover (Root)
├── Popover.Trigger (optional, or use Button directly)
└── Popover.Content
└── Popover.Dialog
├── Popover.Arrow (optional)
├── Popover.Heading (optional)
└── Contentv3 中的新功能
Popover.Arrow 组件
在 v2 中,箭头通过根 Popover 上的 showArrow 布尔 prop 控制。在 v3 中,Popover.Arrow 是一个放置在 Popover.Content 内部的专用组件,让你可以完全控制其渲染:
<Popover>
<Button>Open</Button>
<Popover.Content>
<Popover.Arrow className="custom-arrow" />
<Popover.Dialog>
<div>Content</div>
</Popover.Dialog>
</Popover.Content>
</Popover>Popover.Arrow 也接受 render prop,可完全自定义箭头的渲染。
受控打开状态
受控的打开状态仍保留在根 Popover 组件上,prop 名称与 v2 一致:
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
isOpen | boolean | - | 控制 Popover 的可见性(受控) |
defaultOpen | boolean | false | 初始打开状态(非受控) |
onOpenChange | (isOpen: boolean) => void | - | 打开状态变化时触发 |
自定义渲染函数
Popover.Content 与 Popover.Arrow 都支持 render prop,让你可以在高级场景下用自定义渲染函数覆盖默认 DOM 元素。
总结
- 组件结构:必须使用复合组件(
Popover.Content、Popover.Dialog等) - 触发器:可以使用
Popover.Trigger,或直接将 Button 作为子节点 - 内容包装:内容必须放在
Popover.Dialog中 - 箭头:移除
showArrowprop——改用Popover.Arrow子组件 - 标题:改用
Popover.Heading组件 - prop 移动位置:
placement、offset、shouldFlip移到Popover.Content上 - 移除样式 prop:
size、color、radius、shadow—— 请改用 Tailwind CSS - 移除 backdrop:
backdropprop 已移除 - 移除 motion:
motionProps已移除,动画机制已不同 - 移除 classNames:改在各子组件上使用
classNameprop