Components

弹出框

¥Popover

在门户中显示富文本内容,由按钮触发。

import * as React from "react";
import { Popover } from "radix-ui";
import { MixerHorizontalIcon, Cross2Icon } from "@radix-ui/react-icons";
import "./styles.css";
const PopoverDemo = () => (
<Popover.Root>
<Popover.Trigger asChild>
<button className="IconButton" aria-label="Update dimensions">
<MixerHorizontalIcon />
</button>
</Popover.Trigger>
<Popover.Portal>
<Popover.Content className="PopoverContent" sideOffset={5}>
<div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
<p className="Text" style={{ marginBottom: 10 }}>
Dimensions
</p>
<fieldset className="Fieldset">
<label className="Label" htmlFor="width">
Width
</label>
<input className="Input" id="width" defaultValue="100%" />
</fieldset>
<fieldset className="Fieldset">
<label className="Label" htmlFor="maxWidth">
Max. width
</label>
<input className="Input" id="maxWidth" defaultValue="300px" />
</fieldset>
<fieldset className="Fieldset">
<label className="Label" htmlFor="height">
Height
</label>
<input className="Input" id="height" defaultValue="25px" />
</fieldset>
<fieldset className="Fieldset">
<label className="Label" htmlFor="maxHeight">
Max. height
</label>
<input className="Input" id="maxHeight" defaultValue="none" />
</fieldset>
</div>
<Popover.Close className="PopoverClose" aria-label="Close">
<Cross2Icon />
</Popover.Close>
<Popover.Arrow className="PopoverArrow" />
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
export default PopoverDemo;

Features

    Can be controlled or uncontrolled.

    Customize side, alignment, offsets, collision handling.

    Optionally render a pointing arrow.

    Focus is fully managed and customizable.

    Supports modal and non-modal modes.

    Dismissing and layering behavior is highly customizable.

安装

¥Installation

从命令行安装组件。

¥Install the component from your command line.

npm install @radix-ui/react-popover

结构

¥Anatomy

导入所有部分并将它们组合在一起。

¥Import all parts and piece them together.

import { Popover } from "radix-ui";
export default () => (
<Popover.Root>
<Popover.Trigger />
<Popover.Anchor />
<Popover.Portal>
<Popover.Content>
<Popover.Close />
<Popover.Arrow />
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);

API 参考

¥API Reference

¥Root

包含弹出窗口的所有部分。

¥Contains all the parts of a popover.

PropTypeDefault
defaultOpen
boolean
No default value
open
boolean
No default value
onOpenChange
function
No default value
modal
boolean
false

触发器

¥Trigger

切换弹出窗口的按钮。默认情况下,Popover.Content 将根据触发器进行定位。

¥The button that toggles the popover. By default, the Popover.Content will position itself against the trigger.

PropTypeDefault
asChild
boolean
false
Data attributeValues
[data-state]"open" | "closed"

锚点

¥Anchor

用于定位 Popover.Content 的可选元素。如果不使用 RSC,内容将与 Popover.Trigger 并排放置。

¥An optional element to position the Popover.Content against. If this part is not used, the content will position alongside the Popover.Trigger.

PropTypeDefault
asChild
boolean
false

门户

¥Portal

使用时,将内容部分传送到 body 中。

¥When used, portals the content part into the body.

PropTypeDefault
forceMount
boolean
No default value
container
HTMLElement
document.body

内容

¥Content

弹出窗口打开时弹出的组件。

¥The component that pops out when the popover is open.

PropTypeDefault
asChild
boolean
false
onOpenAutoFocus
function
No default value
onCloseAutoFocus
function
No default value
onEscapeKeyDown
function
No default value
onPointerDownOutside
function
No default value
onFocusOutside
function
No default value
onInteractOutside
function
No default value
forceMount
boolean
No default value
side
enum
"bottom"
sideOffset
number
0
align
enum
"center"
alignOffset
number
0
avoidCollisions
boolean
true
collisionBoundary
Boundary
[]
collisionPadding
number | Padding
0
arrowPadding
number
0
sticky
enum
"partial"
hideWhenDetached
boolean
false
Data attributeValues
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS VariableDescription
--radix-popover-content-transform-originThe transform-origin computed from the content and arrow positions/offsets
--radix-popover-content-available-widthThe remaining width between the trigger and the boundary edge
--radix-popover-content-available-heightThe remaining height between the trigger and the boundary edge
--radix-popover-trigger-widthThe width of the trigger
--radix-popover-trigger-heightThe height of the trigger

箭头

¥Arrow

一个可选的箭头元素,用于与弹出窗口一起渲染。这可以用来帮助在视觉上将锚点与 Popover.Content 链接起来。必须在 Popover.Content 中渲染。

¥An optional arrow element to render alongside the popover. This can be used to help visually link the anchor with the Popover.Content. Must be rendered inside Popover.Content.

PropTypeDefault
asChild
boolean
false
width
number
10
height
number
5

关闭

¥Close

关闭打开的弹出窗口的按钮。

¥The button that closes an open popover.

PropTypeDefault
asChild
boolean
false

示例

¥Examples

限制内容大小

¥Constrain the content size

你可能需要限制内容的宽度,使其与触发器的宽度匹配。你可能还需要限制其高度,使其不超过视口。

¥You may want to constrain the width of the content so that it matches the trigger width. You may also want to constrain its height to not exceed the viewport.

为了支持此功能,我们公开了几个 CSS 自定义属性,例如 --radix-popover-trigger-width--radix-popover-content-available-height。使用它们来限制内容尺寸。

¥We expose several CSS custom properties such as --radix-popover-trigger-width and --radix-popover-content-available-height to support this. Use them to constrain the content dimensions.

// index.jsx
import { Popover } from "radix-ui";
import "./styles.css";
export default () => (
<Popover.Root>
<Popover.Trigger></Popover.Trigger>
<Popover.Portal>
<Popover.Content className="PopoverContent" sideOffset={5}>
</Popover.Content>
</Popover.Portal>
</Popover.Root>
);
/* styles.css */
.PopoverContent {
width: var(--radix-popover-trigger-width);
max-height: var(--radix-popover-content-available-height);
}

原点感知动画

¥Origin-aware animations

我们公开了一个 CSS 自定义属性 --radix-popover-content-transform-origin。使用它来根据 sidesideOffsetalignalignOffset 以及任何碰撞,从其计算出的原点为内容设置动画。

¥We expose a CSS custom property --radix-popover-content-transform-origin. Use it to animate the content from its computed origin based on side, sideOffset, align, alignOffset and any collisions.

// index.jsx
import { Popover } from "radix-ui";
import "./styles.css";
export default () => (
<Popover.Root>
<Popover.Trigger></Popover.Trigger>
<Popover.Portal>
<Popover.Content className="PopoverContent"></Popover.Content>
</Popover.Portal>
</Popover.Root>
);
/* styles.css */
.PopoverContent {
transform-origin: var(--radix-popover-content-transform-origin);
animation: scaleIn 0.5s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}

碰撞感知动画

¥Collision-aware animations

我们公开了 data-sidedata-align 属性。它们的值将在运行时更改以反映碰撞。使用它们来创建碰撞和方向感知动画。

¥We expose data-side and data-align attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations.

// index.jsx
import { Popover } from "radix-ui";
import "./styles.css";
export default () => (
<Popover.Root>
<Popover.Trigger></Popover.Trigger>
<Popover.Portal>
<Popover.Content className="PopoverContent"></Popover.Content>
</Popover.Portal>
</Popover.Root>
);
/* styles.css */
.PopoverContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.PopoverContent[data-side="top"] {
animation-name: slideUp;
}
.PopoverContent[data-side="bottom"] {
animation-name: slideDown;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

使用自定义锚点

¥With custom anchor

如果你不想使用触发器作为锚点,可以将内容锚定到另一个元素。

¥You can anchor the content to another element if you do not want to use the trigger as the anchor.

// index.jsx
import { Popover } from "radix-ui";
import "./styles.css";
export default () => (
<Popover.Root>
<Popover.Anchor asChild>
<div className="Row">
Row as anchor <Popover.Trigger>Trigger</Popover.Trigger>
</div>
</Popover.Anchor>
<Popover.Portal>
<Popover.Content></Popover.Content>
</Popover.Portal>
</Popover.Root>
);
/* styles.css */
.Row {
background-color: gainsboro;
padding: 20px;
}

可访问性

¥Accessibility

遵循 对话框 WAI-ARIA 设计模式

¥Adheres to the Dialog WAI-ARIA design pattern.

键盘交互

¥Keyboard Interactions

KeyDescription
Space
Opens/closes the popover.
Enter
Opens/closes the popover.
Tab
Moves focus to the next focusable element
Shift + Tab
Moves focus to the previous focusable element
Esc
Closes the popover and moves focus to Popover.Trigger.

自定义 API

¥Custom APIs

通过将原始部分抽象到你自己的组件中来创建你自己的 API。

¥Create your own API by abstracting the primitive parts into your own component.

抽象箭头并设置默认配置

¥Abstract the arrow and set default configuration

此示例抽象了 Popover.Arrow 部分并设置了默认的 sideOffset 配置。

¥This example abstracts the Popover.Arrow part and sets a default sideOffset configuration.

用法

¥Usage

import { Popover, PopoverTrigger, PopoverContent } from "./your-popover";
export default () => (
<Popover>
<PopoverTrigger>Popover trigger</PopoverTrigger>
<PopoverContent>Popover content</PopoverContent>
</Popover>
);

实现

¥Implementation

// your-popover.jsx
import * as React from "react";
import { Popover as PopoverPrimitive } from "radix-ui";
export const Popover = PopoverPrimitive.Root;
export const PopoverTrigger = PopoverPrimitive.Trigger;
export const PopoverContent = React.forwardRef(
({ children, ...props }, forwardedRef) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content sideOffset={5} {...props} ref={forwardedRef}>
{children}
<PopoverPrimitive.Arrow />
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
),
);