ProComponents, templates & AI tooling
HeroUI
27.7k

Modal 模态框

用于聚焦用户交互与重要内容的对话框遮罩层。

引入

import { Modal } from "@heroui/react";

用法

"use client";

import {Rocket} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

组件结构

导入 Modal 组件后,可通过点语法访问所有子部分。

import {Modal, Button} from "@heroui/react";

export default () => (
  <Modal>
    <Button>Open Modal</Button>
    <Modal.Backdrop>
      <Modal.Container>
        <Modal.Dialog>
          <Modal.CloseTrigger /> {/* Optional: Close button */}
          <Modal.Header>
            <Modal.Icon /> {/* Optional: Icon */}
            <Modal.Heading />
          </Modal.Header>
          <Modal.Body />
          <Modal.Footer />
        </Modal.Dialog>
      </Modal.Container>
    </Modal.Backdrop>
  </Modal>
);

位置

"use client";

import {Rocket} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

遮罩变体

"use client";

import {Rocket} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

尺寸

"use client";

import {Rocket} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

自定义遮罩

"use client";

import {Sparkles} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

关闭行为

isDismissable

控制是否允许通过点击遮罩关闭模态框。默认为 true。设为 false 时需通过明确操作关闭。

isKeyboardDismissDisabled

控制是否允许通过 ESC 关闭模态框。设为 true 时将禁用 ESC,用户须通过明确操作关闭。

"use client";

import {CircleInfo} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

关闭方式

使用 slot="close"

关闭模态框的最简方式:为模态框内任意 Button 添加 slot="close",点击即可自动关闭。

使用 Dialog 渲染属性

通过 Dialog 的渲染属性访问 close 方法,可完全控制关闭时机与方式,并在关闭前加入自定义逻辑。

"use client";

import {CircleCheck, CircleInfo} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

滚动行为

"use client";

import {Button, Label, Modal, Radio, RadioGroup} from "@heroui/react";
import {useState} from "react";

受控状态

配合 React.useState()

使用 React 的 useState 管理模态框开关,适合简单场景。

状态: 关闭

配合 useOverlayState()

使用 useOverlayState 获得更简洁的 API,内置 open()close()toggle() 等方法。

状态: 关闭

"use client";

import {CircleCheck} from "@gravity-ui/icons";
import {Button, Modal, useOverlayState} from "@heroui/react";
import React from "react";

带表单

"use client";

import {Envelope} from "@gravity-ui/icons";
import {Button, Input, Label, Modal, Surface, TextField} from "@heroui/react";

自定义触发器

"use client";

import {Gear} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";

自定义动画

"use client";

import {ArrowUpFromLine, Sparkles} from "@gravity-ui/icons";
import {Button, Modal} from "@heroui/react";
import React from "react";

自定义 Portal

在自定义容器内渲染模态框,而非 document.body

为容器应用 transform: translateZ(0) 以创建新的层叠上下文。

"use client";

import {Button, Modal} from "@heroui/react";
import {useCallback, useRef, useState} from "react";

样式

传入 Tailwind CSS 类

import {Modal, Button} from "@heroui/react";

function CustomModal() {
  return (
    <Modal>
      <Button>Open Modal</Button>
      <Modal.Backdrop className="bg-black/80">
        <Modal.Container className="items-start pt-20">
          <Modal.Dialog className="bg-linear-to-br from-purple-500 to-pink-500 text-white">
            <Modal.CloseTrigger />
            <Modal.Header>
              <Modal.Heading>Custom Styled Modal</Modal.Heading>
            </Modal.Header>
            <Modal.Body>
              <p>This modal has custom styling applied via Tailwind classes</p>
            </Modal.Body>
            <Modal.Footer>
              <Button slot="close">Close</Button>
            </Modal.Footer>
          </Modal.Dialog>
        </Modal.Container>
      </Modal.Backdrop>
    </Modal>
  );
}

自定义组件类

要自定义 Modal 的组件类,可使用 @layer components 指令。


了解更多

@layer components {
  .modal__backdrop {
    @apply bg-gradient-to-br from-black/50 to-black/70;
  }

  .modal__dialog {
    @apply rounded-2xl border border-white/10 shadow-2xl;
  }

  .modal__header {
    @apply text-center;
  }

  .modal__close-trigger {
    @apply rounded-full bg-white/10 hover:bg-white/20;
  }
}

HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。

CSS 类

Modal 使用以下 CSS 类(查看源码样式):

基础类

  • .modal__trigger — 打开 Modal 的触发元素
  • .modal__backdrop — Modal 背后的遮罩层
  • .modal__container — 支持 placement 的定位包裹层
  • .modal__dialog — Modal 内容容器
  • .modal__header — 标题与图标区域
  • .modal__body — 主内容区域
  • .modal__footer — 操作区域
  • .modal__close-trigger — 关闭按钮元素

遮罩变体

  • .modal__backdrop--opaque — 不透明有色遮罩(默认)
  • .modal__backdrop--blur — 带玻璃效果的模糊遮罩
  • .modal__backdrop--transparent — 透明遮罩(无叠加层)

滚动变体

  • .modal__container--scroll-outside — 允许整个 Modal 滚动
  • .modal__dialog--scroll-inside — 限制 Modal 高度,由 body 区域滚动
  • .modal__body--scroll-inside — 仅 body 区域可滚动
  • .modal__body--scroll-outside — 允许整页滚动

交互状态

组件支持以下交互状态:

  • 焦点:focus-visible[data-focus-visible="true"] — 应用于触发器、对话框与关闭按钮
  • 悬停:hover[data-hovered="true"] — 应用于关闭按钮悬停
  • 按下:active[data-pressed="true"] — 应用于关闭按钮按下
  • 进入[data-entering] — Modal 打开动画期间
  • 离开[data-exiting] — Modal 关闭动画期间
  • 位置[data-placement="*"] — 基于 Modal 位置(auto、top、center、bottom)

API 参考

Prop类型默认值描述
childrenReactNode-触发器与容器元素

Modal.Trigger

Prop类型默认值描述
childrenReactNode-自定义触发内容
classNamestring-CSS 类

Modal.Backdrop

Prop类型默认值描述
variant"opaque" | "blur" | "transparent""opaque"遮罩叠加样式
isDismissablebooleantrue点击遮罩是否关闭
isKeyboardDismissDisabledbooleanfalse是否禁用 ESC 关闭
isOpenboolean-受控打开状态
onOpenChange(isOpen: boolean) => void-打开状态变化处理函数
classNamestring | (values) => string-遮罩 CSS 类
UNSTABLE_portalContainerHTMLElement-自定义 portal 容器

Modal.Container

Prop类型默认值描述
placement"auto" | "center" | "top" | "bottom""auto"Modal 在屏幕上的位置
scroll"inside" | "outside""inside"滚动行为
size"xs" | "sm" | "md" | "lg" | "cover" | "full""md"Modal 尺寸变体
classNamestring | (values) => string-容器 CSS 类

Modal.Dialog

Prop类型默认值描述
childrenReactNode | ({close}) => ReactNode-内容或渲染函数
classNamestring | (values) => string-CSS 类
rolestring"dialog"ARIA role
aria-labelstring-无障碍标签
aria-labelledbystring-标签元素的 id
aria-describedbystring-描述元素的 id

Modal.Header

Prop类型默认值描述
childrenReactNode-头部内容
classNamestring-CSS 类

Modal.Body

Prop类型默认值描述
childrenReactNode-正文内容
classNamestring-CSS 类

Modal.Footer

Prop类型默认值描述
childrenReactNode-底部内容
classNamestring-CSS 类

Modal.CloseTrigger

Prop类型默认值描述
childrenReactNode-自定义关闭按钮
classNamestring | (values) => string-CSS 类

useOverlayState Hook

import {useOverlayState} from "@heroui/react";

const state = useOverlayState({
  defaultOpen: false,
  onOpenChange: (isOpen) => console.log(isOpen),
});

state.isOpen; // 当前状态
state.open(); // 打开 modal
state.close(); // 关闭 modal
state.toggle(); // 切换状态
state.setOpen(); // 直接设置状态

无障碍

实现 WAI-ARIA Dialog 模式

  • 焦点陷阱:焦点锁定在 Modal 内
  • 键盘ESC 关闭(启用时)、Tab 在元素间循环
  • 屏幕阅读器:正确的 ARIA 属性
  • 滚动锁定:打开时禁用 body 滚动

本页目录