在 React 项目中,@headlessui/react
是一个由 Tailwind Labs 开发的无样式、可访问性良好的 UI 组件库,常用于构建完全自定义风格的对话框(Dialog)、菜单、列表等。
@headlessui/react
提供的 Dialog
、DialogBackdrop
、DialogTitle
是用来创建无障碍对话框(Modal)的核心组件。下面我给你详细介绍它们的作用和用法,并提供一个完整示例。
Dialog
自动处理:
role="dialog"
和 aria-modal="true"
DialogBackdrop
DialogTitle
aria-labelledby
,提升无障碍性。npm install @headlessui/react
# 或
yarn add @headlessui/react
import { useState, Fragment } from 'react';
import { Dialog, DialogBackdrop, DialogTitle } from '@headlessui/react';
export default function MyDialog() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button
onClick={() => setIsOpen(true)}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
打开对话框
</button>
<Dialog open={isOpen} onClose={() => setIsOpen(false)} className="relative z-50">
{/* 背景遮罩 */}
<DialogBackdrop className="fixed inset-0 bg-black/50" />
{/* 对话框内容 */}
<div className="fixed inset-0 flex items-center justify-center p-4">
<Dialog.Panel className="mx-auto max-w-sm rounded bg-white p-6 shadow-lg">
<DialogTitle className="text-lg font-bold">
提示信息
</DialogTitle>
<p className="mt-2 text-gray-600">
这是使用 @headlessui/react 创建的无障碍对话框。
</p>
<div className="mt-4 flex justify-end gap-2">
<button
className="px-4 py-2 rounded bg-gray-200 hover:bg-gray-300"
onClick={() => setIsOpen(false)}
>
取消
</button>
<button
className="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600"
onClick={() => setIsOpen(false)}
>
确定
</button>
</div>
</Dialog.Panel>
</div>
</Dialog>
</>
);
}
Dialog
open
控制是否显示onClose
用于关闭逻辑(点击遮罩或按 ESC 时触发)DialogBackdrop
Dialog
的子组件Transition
添加渐入渐出效果DialogTitle
aria-labelledby
,提升可访问性Dialog.Panel
@headlessui/react
的最新版本用 Dialog.Panel
,旧版本可以直接写内容)如果你想要动画,可以结合 Transition
组件使用:
import { Dialog, DialogBackdrop, DialogPanel, DialogTitle, Transition } from '@headlessui/react'
<Transition show={isOpen}>
<Dialog ...>
<Transition.Child
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<DialogBackdrop className="fixed inset-0 bg-black/50" />
</Transition.Child>
<Transition.Child
enter="ease-out duration-300"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<DialogPanel className="fixed inset-0 flex items-center justify-center">
...
</DialogPanel>
</Transition.Child>
</Dialog>
</Transition>
这样可以让背景和对话框都有过渡动画。
Dialog
:核心容器,提供无障碍、焦点管理、ESC 关闭等功能DialogBackdrop
:背景遮罩,阻止点击外部区域DialogTitle
:标题,自动关联 ARIA,提高无障碍性Dialog.Panel
、Transition
使用,实现完整的模态弹窗