Components

对话框

叠加在主窗口或另一个对话框窗口上的窗口, 使下面的内容变得无效。

import * as React from "react";
import { Dialog } from "radix-ui";
import { Cross2Icon } from "@radix-ui/react-icons";
import "./styles.css";
const DialogDemo = () => (
<Dialog.Root>
<Dialog.Trigger asChild>
<button className="Button violet">Edit profile</button>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="DialogOverlay" />
<Dialog.Content className="DialogContent">
<Dialog.Title className="DialogTitle">Edit profile</Dialog.Title>
<Dialog.Description className="DialogDescription">
Make changes to your profile here. Click save when you're done.
</Dialog.Description>
<fieldset className="Fieldset">
<label className="Label" htmlFor="name">
Name
</label>
<input className="Input" id="name" defaultValue="Pedro Duarte" />
</fieldset>
<fieldset className="Fieldset">
<label className="Label" htmlFor="username">
Username
</label>
<input className="Input" id="username" defaultValue="@peduarte" />
</fieldset>
<div style={{ display: "flex", marginTop: 25, justifyContent: "flex-end" }} >
<Dialog.Close asChild>
<button className="Button green">Save changes</button>
</Dialog.Close>
</div>
<Dialog.Close asChild>
<button className="IconButton" aria-label="Close">
<Cross2Icon />
</button>
</Dialog.Close>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
export default DialogDemo;

Features

    支持模态和非模态模式。

    焦点会自动被限制在模态内部。

    可以是受控或非受控。

    通过 Title Description 组件管理屏幕阅读器的公告。

    Esc 键会自动关闭组件。

安装

从命令行安装组件。

npm install @radix-ui/react-dialog

结构

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

import { Dialog } from "radix-ui";
export default () => (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.Close />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);

API 参考

根部件

包含对话框的所有部分。

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

触发器

打开对话框的按钮。

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

门户

使用时,将您的叠加和内容部分传送到 body 中。

PropTypeDefault
forceMount
boolean
No default value
container
HTMLElement
document.body

覆盖层

当对话框打开时,覆盖视图的无效部分的层。

PropTypeDefault
asChild
boolean
false
forceMount
boolean
No default value
Data attributeValues
[data-state]"open" | "closed"

内容

包含在打开对话框中渲染的内容。

PropTypeDefault
asChild
boolean
false
forceMount
boolean
No default value
onOpenAutoFocus
function
No default value
onCloseAutoFocus
function
No default value
onEscapeKeyDown
function
No default value
onPointerDownOutside
function
No default value
onInteractOutside
function
No default value
Data attributeValues
[data-state]"open" | "closed"

关闭

关闭对话框的按钮。

PropTypeDefault
asChild
boolean
false

标题

一个可访问的标题,在打开对话框时被宣布。

如果您想隐藏标题,请将其包装在我们的 视觉隐藏 工具中,例如 <VisuallyHidden asChild>

PropTypeDefault
asChild
boolean
false

描述

一个可选的可访问描述,在打开对话框时被宣布。

如果您想隐藏描述,请将其包装在我们的 视觉隐藏 工具中,例如 <VisuallyHidden asChild>。如果您完全想要移除描述,请删除此部分并将 aria-describedby={undefined} 传递给 Dialog.Content

PropTypeDefault
asChild
boolean
false

示例

在异步表单提交后关闭

使用受控属性在异步操作完成后以编程方式关闭 Dialog。

import * as React from "react";
import { Dialog } from "radix-ui";
const wait = () => new Promise((resolve) => setTimeout(resolve, 1000));
export default () => {
const [open, setOpen] = React.useState(false);
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger>打开</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<form onSubmit={(event) => { wait().then(() => setOpen(false)); event.preventDefault(); }} >
{/** 一些输入 */}
<button type="submit">提交</button>
</form>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
};

可滚动的覆盖层

将内容移动到覆盖层内以渲染一个具有溢出的对话框。

// index.jsx
import { Dialog } from "radix-ui";
import "./styles.css";
export default () => {
return (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay className="DialogOverlay">
<Dialog.Content className="DialogContent">...</Dialog.Content>
</Dialog.Overlay>
</Dialog.Portal>
</Dialog.Root>
);
};
/* styles.css */
.DialogOverlay {
background: rgba(0 0 0 / 0.5);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: grid;
place-items: center;
overflow-y: auto;
}
.DialogContent {
min-width: 300px;
background: white;
padding: 30px;
border-radius: 4px;
}

自定义门户容器

自定义您的对话框传送到的元素。

import * as React from "react";
import { Dialog } from "radix-ui";
export default () => {
const [container, setContainer] = React.useState(null);
return (
<div>
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal container={container}>
<Dialog.Overlay />
<Dialog.Content>...</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<div ref={setContainer} />
</div>
);
};

可访问性

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

键盘交互

KeyDescription
Space
打开/关闭对话框。
Enter
打开/关闭对话框。
Tab
将焦点移动到下一个可聚焦元素。
Shift + Tab
将焦点移动到上一个可聚焦元素。
Esc
关闭对话框并将焦点移动到 Dialog.Trigger

自定义 API

通过将基本部件抽象为您自己的组件来创建您自己的 API。

抽象覆盖层和关闭按钮

此示例抽象了 Dialog.OverlayDialog.Close 部分。

用法

import { Dialog, DialogTrigger, DialogContent } from "./your-dialog";
export default () => (
<Dialog>
<DialogTrigger>对话框触发器</DialogTrigger>
<DialogContent>对话框内容</DialogContent>
</Dialog>
);

实现

// your-dialog.jsx
import * as React from "react";
import { Dialog as DialogPrimitive } from "radix-ui";
import { Cross1Icon } from "@radix-ui/react-icons";
export const DialogContent = React.forwardRef(
({ children, ...props }, forwardedRef) => (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay />
<DialogPrimitive.Content {...props} ref={forwardedRef}>
{children}
<DialogPrimitive.Close aria-label="关闭">
<Cross1Icon />
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
),
);
export const Dialog = DialogPrimitive.Root;
export const DialogTrigger = DialogPrimitive.Trigger;