Popover 弹出框
在由按钮或任意自定义元素触发后,于 portal 中展示丰富内容。
用法
import { Popover } from '@lenso/ui';此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
// Adapted from HeroUI v3.2.6 popover-basic (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Button, Popover } from "@lenso/ui";import { styles } from "./styles";
export function PopoverBasic() { return ( <div {...stylex.props(styles.row)}> <Popover> <Popover.Trigger render={<Button />}>Click me</Popover.Trigger> <Popover.Portal> <Popover.Positioner sideOffset={8}> <Popover.Popup xstyle={styles.popup}> <Popover.Title>Popover Title</Popover.Title> <Popover.Description xstyle={styles.description}> This is the popover content. You can put any content here. </Popover.Description> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
组件结构
import { Popover } from '@lenso/ui';
export default () => ( <Popover> <Popover.Trigger/> <Popover.Content> <Popover.Arrow /> <Popover.Dialog> <Popover.Heading/> {/* content goes here */} </Popover.Dialog> </Popover.Content> </Popover>)示例
带箭头
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
// Adapted from HeroUI v3.2.6 popover-with-arrow (Apache-2.0).import { Ellipsis } from "@gravity-ui/icons";import * as stylex from "@stylexjs/stylex";import { Button, Popover } from "@lenso/ui";import { styles } from "./styles";
export function PopoverWithArrow() { return ( <div {...stylex.props(styles.row)}> <Popover> <Popover.Trigger render={<Button variant="secondary" />}>With Arrow</Popover.Trigger> <Popover.Portal> <Popover.Positioner sideOffset={8}> <Popover.Popup xstyle={styles.popup}> <Popover.Arrow /> <Popover.Title>Popover with Arrow</Popover.Title> <Popover.Description xstyle={styles.description}> The arrow shows which element triggered the popover. </Popover.Description> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> <Popover> <Popover.Trigger render={<Button isIconOnly aria-label="More options" variant="tertiary" />} > <Button.Icon> <Ellipsis /> </Button.Icon> </Popover.Trigger> <Popover.Portal> <Popover.Positioner sideOffset={10}> <Popover.Popup xstyle={styles.popup}> <Popover.Arrow /> <Popover.Title>Popover with Arrow</Popover.Title> <Popover.Description xstyle={styles.description}> The arrow shows which element triggered the popover. </Popover.Description> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
可交互内容
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
// Adapted from HeroUI v3.2.6 popover-interactive (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Avatar, Button, Popover } from "@lenso/ui";import { useState } from "react";import { styles } from "./styles";
export function PopoverInteractive() { const [isFollowing, setIsFollowing] = useState(false); return ( <div {...stylex.props(styles.profileRow)}> <Popover> <Popover.Trigger aria-label="User profile"> <div {...stylex.props(styles.identity)}> <Avatar size="sm"> <Avatar.Image alt="Sarah Johnson" src="https://img.heroui.chat/image/avatar?w=400&h=400&u=1" /> <Avatar.Fallback>SJ</Avatar.Fallback> </Avatar> <div {...stylex.props(styles.identityText)}> <p {...stylex.props(styles.name)}>Sarah Johnson</p> <p {...stylex.props(styles.handle)}>@sarahj</p> </div> </div> </Popover.Trigger> <Popover.Portal> <Popover.Positioner sideOffset={8}> <Popover.Popup xstyle={styles.profilePopup}> <Popover.Title render={<div />}> <div {...stylex.props(styles.profileHeading)}> <div {...stylex.props(styles.identityLarge)}> <Avatar size="md"> <Avatar.Image alt="Sarah Johnson" src="https://img.heroui.chat/image/avatar?w=400&h=400&u=1" /> <Avatar.Fallback>SJ</Avatar.Fallback> </Avatar> <div> <p {...stylex.props(styles.strong)}>Sarah Johnson</p> <p {...stylex.props(styles.muted)}>@sarahj</p> </div> </div> <Button xstyle={styles.follow} size="sm" variant={isFollowing ? "tertiary" : "primary"} onClick={() => setIsFollowing(!isFollowing)} > {isFollowing ? "Following" : "Follow"} </Button> </div> </Popover.Title> <Popover.Description xstyle={styles.bio}> Product designer and creative director. Building beautiful experiences that matter. </Popover.Description> <div {...stylex.props(styles.statistics)}> <div> <span {...stylex.props(styles.strong)}>892</span> <span {...stylex.props(styles.statisticLabel)}>Following</span> </div> <div> <span {...stylex.props(styles.strong)}>12.5K</span> <span {...stylex.props(styles.statisticLabel)}>Followers</span> </div> </div> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
位置
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
// Adapted from HeroUI v3.2.6 popover-placement (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Button, Popover } from "@lenso/ui";import { styles } from "./styles";
export function PopoverPlacement() { return ( <div {...stylex.props(styles.grid)}> <div /> <Popover> <Popover.Trigger render={<Button xstyle={styles.fullWidth} variant="tertiary" />}> Top </Popover.Trigger> <Popover.Portal> <Popover.Positioner side="top" sideOffset={8}> <Popover.Popup> <Popover.Arrow /> <p {...stylex.props(styles.small)}>Top placement</p> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> <div /> <Popover> <Popover.Trigger render={<Button xstyle={styles.fullWidth} variant="tertiary" />}> Left </Popover.Trigger> <Popover.Portal> <Popover.Positioner side="left" sideOffset={8}> <Popover.Popup> <Popover.Arrow /> <p {...stylex.props(styles.small)}>Left placement</p> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> <div {...stylex.props(styles.center)}> <span {...stylex.props(styles.muted)}>Click buttons</span> </div> <Popover> <Popover.Trigger render={<Button xstyle={styles.fullWidth} variant="tertiary" />}> Right </Popover.Trigger> <Popover.Portal> <Popover.Positioner side="right" sideOffset={8}> <Popover.Popup> <Popover.Arrow /> <p {...stylex.props(styles.small)}>Right placement</p> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> <div /> <Popover> <Popover.Trigger render={<Button xstyle={styles.fullWidth} variant="tertiary" />}> Bottom </Popover.Trigger> <Popover.Portal> <Popover.Positioner side="bottom" sideOffset={8}> <Popover.Popup> <Popover.Arrow /> <p {...stylex.props(styles.small)}>Bottom placement</p> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> <div /> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
渲染函数
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
// Adapted from HeroUI v3.2.6 popover-render-function (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Button, Popover } from "@lenso/ui";import { styles } from "./styles";
export function RenderFunction() { return ( <div {...stylex.props(styles.row)}> <Popover> <Popover.Trigger render={<Button />}>Click me</Popover.Trigger> <Popover.Portal> <Popover.Positioner sideOffset={8}> <Popover.Popup xstyle={styles.popup} render={(props) => <div {...props} data-custom="foo" />} > <Popover.Title>Popover Title</Popover.Title> <Popover.Description xstyle={styles.description}> This is the popover content. You can put any content here. </Popover.Description> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> </div> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
自定义样式
Tailwind CSS
此预览复用英文版适配,不代表中文源示例已完成本地实现。
"use client";
// Adapted from HeroUI v3.2.6 popover-custom-styles (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Button, Popover } from "@lenso/ui";import { styles } from "./styles";
export function CustomStyles() { return ( <Popover> <Popover.Trigger render={<Button variant="secondary" />}>Details</Popover.Trigger> <Popover.Portal> <Popover.Positioner sideOffset={8}> <Popover.Popup xstyle={styles.customPopup}> <div {...stylex.props(styles.customDialog)}> <div aria-hidden="true" {...stylex.props(styles.highlight)} /> <Popover.Title xstyle={styles.customHeading}>Keyboard shortcuts</Popover.Title> <dl {...stylex.props(styles.shortcuts)}> <div {...stylex.props(styles.shortcut)}> <dt {...stylex.props(styles.muted)}>Save</dt> <dd {...stylex.props(styles.key)}>⌘ S</dd> </div> <div {...stylex.props(styles.shortcut)}> <dt {...stylex.props(styles.muted)}>Search</dt> <dd {...stylex.props(styles.key)}>⌘ K</dd> </div> </dl> </div> </Popover.Popup> </Popover.Positioner> </Popover.Portal> </Popover> );}Local adaptation source above. Derived from HeroUI v3.2.6 source.
全局 CSS
若要自定义组件类,可使用 @layer components 指令。了解更多。
@layer components { .popover { @apply rounded-xl shadow-2xl; }
.popover__dialog { @apply p-4; }
.popover__heading { @apply text-lg font-bold; }}样式参考
HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。
CSS 类
Popover 使用以下 CSS 类(查看源码样式):
基础类 [!toc]
.popover- Popover 根容器样式.popover__dialog- 对话框内容包裹层.popover__heading- 标题文本样式.popover__trigger- 触发元素样式
交互状态
组件支持以下动画相关状态:
- 进入:
[data-entering]— Popover 出现过程中应用 - 离开:
[data-exiting]— Popover 消失过程中应用 - 位置:
[data-placement="*"]— 根据 Popover 位置应用 - 焦点:
:focus-visible或[data-focus-visible="true"]
API 参考
Popover
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | React.ReactNode | - | 触发器与内容元素 |
isOpen | boolean | - | 控制 Popover 是否可见(受控) |
defaultOpen | boolean | false | 初始打开状态(非受控) |
onOpenChange | (isOpen: boolean) => void | - | 打开状态变化时调用 |
Popover.Content
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | React.ReactNode | - | 在 Popover 中展示的内容 |
placement | "top" | "bottom" | "left" | "right" (及变体) | "bottom" | Popover 的位置 |
offset | number | 8 | 与触发元素的距离 |
shouldFlip | boolean | true | 是否允许 Popover 改变方向以适配空间 |
className | string | - | 额外的 CSS 类名 |
render | DOMRenderFunction<keyof React.JSX.IntrinsicElements, PopoverRenderProps> | - | 通过自定义渲染函数覆盖默认的 DOM 元素。 |
Popover.Dialog
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | React.ReactNode | - | 对话框内容 |
className | string | - | 额外的 CSS 类名 |
Popover.Trigger
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | React.ReactNode | - | 触发 Popover 的元素 |
className | string | - | 额外的 CSS 类名 |
Popover.Arrow
| Prop | 类型 | 默认值 | 描述 |
|---|---|---|---|
children | React.ReactNode | - | 自定义箭头元素 |
className | string | - | 额外的 CSS 类名 |
render | DOMRenderFunction<keyof React.JSX.IntrinsicElements, OverlayArrowRenderProps> | - | 通过自定义渲染函数覆盖默认的 DOM 元素。 |