# 对话框

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

## Features

- 支持模态和非模态模式。

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

- 可以是受控或非受控。

- 通过 `Title` 和<!-- --> `Description` 组件管理屏幕阅读器的公告。

- Esc 键会自动关闭组件。

## [Anatomy](#anatomy)

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

```jsx
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 参考](#api-参考)

### [根部件](#根部件)

包含对话框的所有部分。

| Prop           | Type       | Default          |
| -------------- | ---------- | ---------------- |
| `defaultOpen`  | `boolean`  | No default value |
| `open`         | `boolean`  | No default value |
| `onOpenChange` | `function` | No default value |
| `modal`        | `boolean`  | `true`           |

### [触发器](#触发器)

打开对话框的按钮。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

| Data attribute | Values               |
| -------------- | -------------------- |
| `[data-state]` | `"open" \| "closed"` |

### [门户](#门户)

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

| Prop         | Type          | Default          |
| ------------ | ------------- | ---------------- |
| `forceMount` | `boolean`     | No default value |
| `container`  | `HTMLElement` | `document.body`  |

### [覆盖层](#覆盖层)

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

| Prop         | Type      | Default          |
| ------------ | --------- | ---------------- |
| `asChild`    | `boolean` | `false`          |
| `forceMount` | `boolean` | No default value |

| Data attribute | Values               |
| -------------- | -------------------- |
| `[data-state]` | `"open" \| "closed"` |

### [内容](#内容)

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

| Prop                   | Type       | Default          |
| ---------------------- | ---------- | ---------------- |
| `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 attribute | Values               |
| -------------- | -------------------- |
| `[data-state]` | `"open" \| "closed"` |

### [关闭](#关闭)

关闭对话框的按钮。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

### [标题](#标题)

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

如果您想隐藏标题，请将其包装在我们的 [视觉隐藏](../utilities/visually-hidden) 工具中，例如 `<VisuallyHidden asChild>`。

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

### [描述](#描述)

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

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

| Prop      | Type      | Default |
| --------- | --------- | ------- |
| `asChild` | `boolean` | `false` |

## [示例](#示例)

### [在异步表单提交后关闭](#在异步表单提交后关闭)

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

```jsx
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>
  );
};
```

### [可滚动的覆盖层](#可滚动的覆盖层)

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

```jsx
// 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>
  );
};
```

```css
/* 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;
}
```

### [自定义门户容器](#自定义门户容器)

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

```jsx
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 设计模式](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal)。

### [键盘交互](#键盘交互)

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

## [自定义 API](#自定义-api)

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

### [抽象覆盖层和关闭按钮](#抽象覆盖层和关闭按钮)

此示例抽象了 `Dialog.Overlay` 和 `Dialog.Close` 部分。

#### 用法

```jsx
import { Dialog, DialogTrigger, DialogContent } from "./your-dialog";

export default () => (
  <Dialog>
    <DialogTrigger>对话框触发器</DialogTrigger>

    <DialogContent>对话框内容</DialogContent>
  </Dialog>
);
```

#### 实现

```jsx
// 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;
```

<!--$-->

<!--/$-->
