通过覆盖在主要内容上的窗口将用户的注意力专门集中在信息上。

演示

import {
  Button,
  CloseButton,
  Dialog,
  DialogBackdrop,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
} from "@resolid/react-ui";

export default function App() {
  return (
    <Dialog>
      <DialogTrigger render={(props) => <Button {...props} />}>打开对话框</DialogTrigger>
      <DialogPortal>
        <DialogBackdrop />
        <DialogContent className="md:max-w-128 max-w-[calc(100vw-6rem) my-20">
          <DialogClose
            className={"absolute end-2 top-2 p-1"}
            render={(props) => <CloseButton {...props} />}
          />
          <DialogTitle className={"p-4"}>对话框标题</DialogTitle>
          <DialogDescription className={"p-4 pt-1"}>
            这是一个对话框示例,你可以在这里放置相关的提示信息、确认内容或者操作说明。内容可以根据需求进行修改,以适应不同的业务场景。
          </DialogDescription>
          <div className={"flex justify-end gap-4 p-4 pt-1"}>
            <DialogClose
              render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
            >
              取消
            </DialogClose>
            <Button color={"neutral"}>确定</Button>
          </div>
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

用法

import {
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogBackdrop,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from "@resolid/react-ui";
  • Dialog: 包含对话框的所有部分。
  • DialogTrigger: 包装将打开对话框的控件。
  • DialogPortal: 当对话框打开时,将其子项传送到 body 中。
  • DialogBackdrop: 对话框打开时覆盖视图惰性部分的层。
  • DialogContent: 包含对话框打开时要呈现的内容。
  • DialogTitle: 打开对话框时要宣布的可访问标题。
  • DialogDescription: 打开对话框时要宣布的可选描述。
  • DialogClose: 关闭对话框的控件。

对话框默认只有必需的样式,你可以通过 DialogContentDialogTitleDialogDescriptionclassName 自定义。

<Dialog>
  <DialogTrigger />
  <DialogPortal>
    <DialogBackdrop />
    <DialogContent>
      <DialogClose />
      <DialogTitle />
      <DialogDescription />
    </DialogContent>
  </DialogPortal>
</Dialog>

特点

  • 遵循 WAI ARIA Dialog 设计模式。
  • 支持 dialogalertdialog 角色。
  • 管理带有 TitleDescription 组件的屏幕阅读器公告。
  • 当它打开时,焦点被捕获并且滚动被阻止。
  • 按下 Esc 关闭对话框。
  • 可以是受控的,也可以是不受控的。

举例

位置

使用 placement 属性更改对话框组件的位置,对话框支持 topcenterbottom 三个位置。

import {
  Button,
  CloseButton,
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogBackdrop,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogClose,
} from "@resolid/react-ui";

export default function App() {
  const placements = [
    { value: "top", name: "顶部" },
    { value: "bottom", name: "底部" },
    { value: "center", name: "中间" },
  ];

  return (
    <div className={"flex flex-row gap-3"}>
      {placements.map((placement) => {
        return (
          <Dialog key={placement.value} placement={placement.value}>
            <DialogTrigger render={(props) => <Button {...props} />}>
              打开{placement.name}对话框
            </DialogTrigger>
            <DialogPortal>
              <DialogBackdrop />
              <DialogContent className="md:max-w-128 max-w-[calc(100vw-6rem) my-20">
                <DialogClose
                  className={"absolute end-2 top-2 p-1"}
                  render={(props) => <CloseButton {...props} />}
                />
                <DialogTitle className={"p-4"}>对话框标题</DialogTitle>
                <DialogDescription className={"p-4 pt-1"}>
                  这是一个对话框示例,你可以在这里放置相关的提示信息、确认内容或者操作说明。内容可以根据需求进行修改,以适应不同的业务场景。
                </DialogDescription>
                <div className={"flex justify-end gap-4 p-4 pt-1"}>
                  <DialogClose
                    render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
                  >
                    取消
                  </DialogClose>
                  <Button color={"neutral"}>确定</Button>
                </div>
              </DialogContent>
            </DialogPortal>
          </Dialog>
        );
      })}
    </div>
  );
}

嵌套

你可以正常的嵌套对话框。

import {
  Button,
  CloseButton,
  Dialog,
  DialogBackdrop,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
} from "@resolid/react-ui";

export default function App() {
  return (
    <Dialog>
      <DialogTrigger render={(props) => <Button {...props} />}>打开对话框</DialogTrigger>
      <DialogPortal>
        <DialogBackdrop />
        <DialogContent className="md:max-w-128 max-w-[calc(100vw-6rem) my-25">
          <DialogClose
            className={"absolute end-2 top-2 p-1"}
            render={(props) => <CloseButton {...props} />}
          />
          <DialogTitle className={"p-4"}>对话框标题</DialogTitle>
          <DialogDescription className={"p-4 pt-1"}>
            你正在进行一项操作,这可能会影响当前的设置或数据。请确认是否继续?如果不确定,可以先查看相关文档,或者咨询管理员获取更多信息。
          </DialogDescription>
          <div className={"flex justify-end gap-4 p-4 pt-1"}>
            <DialogClose
              render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
            >
              取消
            </DialogClose>
            <Dialog>
              <DialogTrigger render={(props) => <Button color={"danger"} {...props} />}>
                删除
              </DialogTrigger>
              <DialogPortal>
                <DialogBackdrop />
                <DialogContent className="md:max-w-86 max-w-[calc(100vw-6rem) my-20">
                  <DialogClose
                    className={"absolute end-2 top-2 p-1"}
                    render={(props) => <CloseButton {...props} />}
                  />
                  <DialogTitle className={"p-4"}>操作确认</DialogTitle>
                  <DialogDescription className={"p-4 pt-1"}>
                    你正在进行一项操作,这可能会影响当前的设置或数据。请确认是否继续?如果不确定,可以先查看相关文档,或者咨询管理员获取更多信息。
                  </DialogDescription>
                  <div className={"flex justify-end gap-4 p-4 pt-1"}>
                    <DialogClose
                      render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
                    >
                      取消
                    </DialogClose>
                    <Button color={"danger"}>确认</Button>
                  </div>
                </DialogContent>
              </DialogPortal>
            </Dialog>
          </div>
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

滚动行为

使用 scrollBehavior 属性在其内容溢出时更改对话框的滚动行为,支持 insideoutside 两种行为。

import {
  Button,
  CloseButton,
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogBackdrop,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogClose,
  RadioGroup,
  Radio,
} from "@resolid/react-ui";
import { useState } from "react";

export default function App() {
  const [scrollBehavior, setScrollBehavior] = useState("inside");

  return (
    <div className={"flex flex-row items-center gap-5"}>
      <RadioGroup value={scrollBehavior} onChange={setScrollBehavior}>
        <div className={"flex flex-row gap-5"}>
          <Radio value="inside">内部</Radio>
          <Radio value="outside">外部</Radio>
        </div>
      </RadioGroup>
      <Dialog scrollBehavior={scrollBehavior}>
        <DialogTrigger render={(props) => <Button {...props} />}>打开对话框</DialogTrigger>
        <DialogPortal>
          <DialogBackdrop />
          <DialogContent className="md:max-w-160 max-w-[calc(100vw-6rem) my-20 flex flex-col">
            <DialogClose
              className={"absolute end-2 top-2 p-1"}
              render={(props) => <CloseButton {...props} />}
            />
            <DialogTitle className={"p-4"}>对话框标题</DialogTitle>
            <div
              className={
                scrollBehavior === "inside"
                  ? "scrollbar scrollbar-thin flex-1 overflow-y-auto overscroll-contain"
                  : ""
              }
            >
              <DialogDescription className={"p-4 pt-1"}>
                这是一个对话框示例,你可以在这里放置相关的提示信息、确认内容或者操作说明。内容可以根据需求进行修改,以适应不同的业务场景。
              </DialogDescription>
              <article className={"p-4 py-1"}>
                {Array.from({ length: 16 }, (x, i) => i + 1).map((i) => (
                  <p key={i} className={"mb-4"}>
                    这是一个演示文本,用于填充内容,以便展示排版效果。你可以根据需要替换为实际内容。
                  </p>
                ))}
              </article>
            </div>
          </DialogContent>
        </DialogPortal>
      </Dialog>
    </div>
  );
}

警告对话框

设置 role: "alertdialog" 属性将对话框组件更改为警告对话框。

import {
  Button,
  CloseButton,
  Dialog,
  DialogBackdrop,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
} from "@resolid/react-ui";

export default function App() {
  return (
    <Dialog role={"alertdialog"}>
      <DialogTrigger render={(props) => <Button {...props} />}>打开对话框</DialogTrigger>
      <DialogPortal>
        <DialogBackdrop />
        <DialogContent className="md:max-w-128 max-w-[calc(100vw-6rem) my-20">
          <DialogClose
            className={"absolute end-2 top-2 p-1"}
            render={(props) => <CloseButton {...props} />}
          />
          <DialogTitle className={"p-4"}>对话框标题</DialogTitle>
          <DialogDescription className={"p-4 pt-1"}>
            你正在进行一项操作,这可能会影响当前的设置或数据。请确认是否继续?如果不确定,可以先查看相关文档,或者咨询管理员获取更多信息。
          </DialogDescription>
          <div className={"flex justify-end gap-4 p-4 pt-1"}>
            <DialogClose
              render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
            >
              取消
            </DialogClose>
            <Button color={"danger"}>确认</Button>
          </div>
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

焦点管理

对话框打开会自动将焦点设置在第一个可用的元素上(一般默认是关闭按钮),关闭时会自动返回焦点,你可以通过设置 initialFocusfinalFocus 属性来自定义焦点目标。

import {
  Button,
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogBackdrop,
  DialogContent,
  DialogTitle,
  DialogClose,
  Input,
} from "@resolid/react-ui";
import { useRef } from "react";

export default function App() {
  const initialRef = useRef(null);
  const finalRef = useRef(null);

  return (
    <div className={"flex flex-row gap-3"}>
      <Dialog initialFocus={initialRef} finalFocus={finalRef}>
        <DialogTrigger render={(props) => <Button {...props} />}>打开对话框</DialogTrigger>

        <DialogPortal>
          <DialogBackdrop />
          <DialogContent className="md:max-w-128 max-w-[calc(100vw-6rem) my-20">
            <DialogTitle className={"p-4"}>对话框标题</DialogTitle>
            <div className={"flex flex-col gap-4 p-4 pt-1"}>
              <div className={"flex flex-col gap-1"}>
                <label htmlFor={"username"}>姓名</label>
                <Input id={"username"} />
              </div>
              <div className={"flex flex-col gap-1"}>
                <label htmlFor={"email"}>邮件</label>
                <Input ref={initialRef} id={"email"} />
              </div>
            </div>
            <div className={"flex justify-end gap-4 p-4 pt-1"}>
              <DialogClose
                render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
              >
                取消
              </DialogClose>
              <Button color={"neutral"}>保存</Button>
            </div>
          </DialogContent>
        </DialogPortal>
      </Dialog>
      <Button color={"neutral"} ref={finalRef}>
        键盘关闭对话框后获得焦点
      </Button>
    </div>
  );
}

关闭确认

此示例显示了一个嵌套的确认对话框,该对话框如果要丢弃父母对话框中输入的文本。

为了实现这一点,应控制两个对话框。当“父级”对话框的 onOpenChange 回调接收到关闭请求时,可以打开“确认”对话框。这样,当用户单击背景,按 ESC 键或单击关闭按钮时,将自动显示确认。

import {
  Button,
  Dialog,
  DialogBackdrop,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
} from "@resolid/react-ui";
import { useState } from "react";

export default function App() {
  const [dialogOpen, setDialogOpen] = useState(false);
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [textareaValue, setTextareaValue] = useState("");

  return (
    <>
      <Dialog
        open={dialogOpen}
        onOpenChange={(open) => {
          if (!open && textareaValue) {
            setConfirmOpen(true);
          } else {
            setTextareaValue("");
            setDialogOpen(open);
          }
        }}
      >
        <DialogTrigger render={(props) => <Button {...props} />}>打开对话框</DialogTrigger>
        <DialogPortal>
          <DialogBackdrop />
          <DialogContent className="my-25 w-96">
            <DialogTitle className={"p-4"}>新推文</DialogTitle>
            <form
              className={"p-4 pt-1"}
              onSubmit={(event) => {
                event.preventDefault();
                setDialogOpen(false);
              }}
            >
              <textarea
                rows={6}
                required
                className={"border-bd-normal w-full rounded-md border px-3 py-2"}
                placeholder={"有什么新想法吗?"}
                onChange={(e) => setTextareaValue(e.target.value)}
              />
              <div className={"flex justify-end gap-4"}>
                <DialogClose
                  render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
                >
                  取消
                </DialogClose>
                <Button type={"submit"} color={"neutral"}>
                  发布
                </Button>
              </div>
            </form>
          </DialogContent>
        </DialogPortal>
      </Dialog>
      <Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>
        <DialogPortal>
          <DialogBackdrop />
          <DialogContent className="my-30 w-96">
            <DialogTitle className={"p-4"}>丢弃推文?</DialogTitle>
            <DialogDescription className={"p-4 pt-1"}>您的推文将丢失。</DialogDescription>
            <div className={"flex justify-end gap-4 p-4 pt-1"}>
              <DialogClose
                render={(props) => <Button color={"neutral"} variant={"soft"} {...props} />}
              >
                返回
              </DialogClose>
              <Button
                color={"danger"}
                onClick={() => {
                  setConfirmOpen(false);
                  setDialogOpen(false);
                }}
              >
                丢弃
              </Button>
            </div>
          </DialogContent>
        </DialogPortal>
      </Dialog>
    </>
  );
}

属性

属性duration简介

动画持续时间

类型number默认值250必须false
属性initialFocus简介

开启后焦点目标

类型number | RefObject<HTMLElement>默认值-必须false
属性finalFocus简介

关闭后焦点目标

类型RefObject<HTMLElement>默认值-必须false
属性scrollBehavior简介

滚动行为

类型"inside" | "outside"默认值"inside"必须false
属性placement简介

放置位置

类型"top" | "center" | "bottom"默认值"top"必须false
属性closeOnEscape简介

按下 Esc 键时关闭

类型boolean默认值true必须false
属性closeOnOutsideClick简介

单击外部时关闭

类型boolean默认值true必须false
属性preventScroll简介

打开时阻止背景页面滚动

类型boolean默认值false必须false
属性role简介

对话框角色

类型"dialog" | "alertdialog"默认值"dialog"必须false
属性open简介

受控打开状态

类型boolean默认值-必须false
属性defaultOpen简介

初始渲染时的默认打开状态

类型boolean默认值false必须false
属性onOpenChange简介

打开状态改变时调用

类型(open: boolean) => void默认值-必须false

建议更改此页面