跳到主要内容

Dialog 对话框Dialog · confirm()

打断当前的事,要人先回应:确认一个操作、补充一两项信息。它是模态的,出现时页面其余部分不可用,所以只在必须打断时才用;只是告知结果请用 Toast。

同一张悬浮卡片

Dialog、Drawer、Sheet、Panel 不是四套东西,而是同一张悬浮卡片(FloatingCard)在不同位置、不同尺寸下的用法:一张圆角卡片,和视口四周留一圈缝,从停靠的那一侧滑入。没有阴影,模态时靠遮罩压暗背景,非模态时靠描边和页面分开。遮罩、焦点圈、滚动锁、Esc、进退场都在 FloatingCard 里,只此一份;卡片里面统一用 FloatingHeader / FloatingBody / FloatingFooter 三个结构件来搭。

组件停靠位置模态用在哪
Dialog 本页居中模态确认、简短的表单
Drawer贴着四边之一模态详情、较长的表单、导航
Sheet贴着底边模态手机上代替对话框和抽屉
Panel贴着四边之一非模态检查器、筛选面板

结构件

Dialog 自带一套“图标 + 标题 + 说明 + 等分按钮”的排版,够用时直接传属性即可(见下文)。需要自己排版的居中卡片,可以直接用 FloatingCard 配三个结构件。

基本用法

图标在标题左侧,下面是说明,底部一到两个等分撑满的按钮。Esc 或点遮罩关闭;关闭后焦点回到打开它的按钮上。

图标的状态色

tone 只改变图标色块的颜色,默认 accent。

居中变体

没有图标的简短确认框用 align="center",标题和说明居中。

尺寸

宽度预设 sm 320、md 400(默认)、lg 560,也可以给数字或 CSS 长度。高度随内容,超出视口时卡片内部滚动。

放表单

children 放在说明和按钮之间。closable 在右上角加一个关闭按钮;initialFocus 指定打开后焦点落在哪个元素上。

alertdialog

需要用户立刻回应、不能随手关掉的打断,用 role="alertdialog" 并关掉 dismissible:Esc 和点遮罩都不再关闭,只能点按钮。给最安全的那个按钮加 data-autofocus,让焦点一开始就落在它上面。

从触发点进场

居中的对话框从打开它的地方放大出来,关闭时缩回同一个点:用指针点开的从点按处,用键盘(Tab 到按钮再按回车)打开的从按钮中心;通过快捷键打开、没有触发元素时(焦点在页面空白处或输入框里)从屏幕中心。快捷键按下时焦点可能还停在某个按钮上,这时传 origin="center" 明确要求从屏幕中心出来;也可以传视口坐标 { x, y }。手机宽度下也一样。

或者按 Shift D 从屏幕中心出来

confirm()

最常见的“确定吗?”不需要自己管开合状态:await confirm(...) 返回一个 Promise,确认得到 true,取消、Esc、点遮罩得到 false。它渲染的是 alertdialog;tone 为 danger 时确认按钮用危险色,焦点默认落在“取消”上。在应用根部挂一个 <Confirmer />(本站已挂)。

规格

面板
圆角 32 · 内边距 24 · 最大宽 400
图标
40 × 40 色块 · 在标题左侧
居中变体
无图标 · 标题与说明居中
进场
从触发点放大:scale 0.6 → 1 · spring-soft 曲线 303ms + 100ms 淡入;没有触发点时从屏幕中心
遮罩
160ms · 变暗 + 模糊 8px
退场
160ms ease-in · 缩回进场的那个点

接口

Dialog

属性类型默认值说明
titleReactNode—标题,自动成为对话框的名字。
descriptionReactNode—说明,自动成为对话框的描述。
iconReactNode—标题左侧的图标位(40×40 的色块)。
tone'neutral' | 'accent' | 'success' | 'warning' | 'danger' | 'info''accent'图标色块的状态色。
actionsReactNode—底部操作区:放一到两个按钮,等分撑满。
childrenReactNode—说明和按钮之间的自定义内容。
size'sm' | 'md' | 'lg' | number | string'md'宽度预设:320 / 400 / 560;或数字(px)、CSS 长度。
align'start' | 'center''start'center:标题与说明居中。
role'dialog' | 'alertdialog''dialog'需要用户立刻回应的打断用 alertdialog。
closablebooleanfalse右上角带一个关闭按钮。
closeLabelstring'关闭'关闭按钮的读屏名称。
origin'trigger' | 'center' | { x: number; y: number }'trigger'从哪里放大进场、缩回哪里。trigger:点按处 / 键盘焦点元素的中心,没有触发元素时屏幕中心;center:屏幕中心;也可以给视口坐标。
open / defaultOpenbooleanfalse开合,受控 / 非受控。
onOpenChange(open: boolean) => void—开合变化时(Esc、点遮罩、关闭按钮、拖拽关闭都会触发)。
dismissiblebooleantrue允许 Esc 和点遮罩关闭。
gapnumber12(窄屏 8)卡片到视口边缘的间隙(px)。
initialFocusRefObject<HTMLElement>—模态时打开后焦点落在哪。默认是卡片里带 data-autofocus 的元素,没有就落在卡片本身。
restoreFocusbooleantrue关闭后把焦点还给打开前的元素。
containerHTMLElement | null—渲染到哪个容器,默认 body。
onExited() => void—退场动画结束、节点卸载后。
aria-label / aria-labelledby / aria-describedbystring—不传时自动接上 FloatingHeader 的标题和说明。

confirm(options)

属性类型默认值说明
title*ReactNode—标题。也可以直接 confirm('一句话')。
descriptionReactNode—说明。
confirmTextReactNode'确定'确认按钮的文字。
cancelTextReactNode'取消'取消按钮的文字。
toneDialogTone—danger:确认按钮用危险色,默认焦点落在“取消”上。
iconReactNode—图标。不传图标时默认用居中变体。
size'sm' | 'md' | 'lg' | number | string—同 Dialog。
align'start' | 'center'—默认:有图标靠左,没有图标居中。
dismissiblebooleantrue允许 Esc / 点遮罩关闭(按“取消”算)。
origin'trigger' | 'center' | { x: number; y: number }'trigger'同 Dialog:从哪里放大进场。

FloatingHeader

属性类型默认值说明
titleReactNode—标题。自动成为卡片的 aria-labelledby。
descriptionReactNode—标题下面的一行说明。自动成为卡片的 aria-describedby。
iconReactNode—标题左边的图标位(40×40 的色块)。
level1 | 2 | 3 | 4 | 5 | 62标题的层级。
closableboolean—是否带关闭按钮。默认跟随卡片的 dismissible。
closeLabelstring'关闭'关闭按钮的读屏名称。
onClose() => void—点关闭按钮时;不传则请求卡片关闭。
childrenReactNode—放在关闭按钮前面的额外操作。

FloatingBody / FloatingFooter

属性类型默认值说明
paddedbooleantrue是否带内边距。内容自己通栏(列表、表格)时关掉。
align'start' | 'end' | 'between' | 'stretch''end'按钮的排法:靠左、靠右、两端、等分撑满。

无障碍

  • role="dialog"(或 alertdialog)加 aria-modal="true";名字和描述自动取自 title 和 description,没有可见标题时必须给 aria-label。
  • 打开时焦点移进对话框:initialFocus 指定的元素 → 带 data-autofocus 的元素 → 对话框本身。Tab 和 Shift Tab 被圈在对话框里循环。
  • Esc 或点遮罩关闭(dismissible={false} 时都不行);关闭后焦点回到打开它的元素。
  • 打开期间页面背景锁定滚动,遮罩后面的内容不可点。
  • alertdialog 会让读屏立刻读出标题和说明,只用于必须马上回应的事。破坏性操作把初始焦点放在“取消”上,confirm() 的 danger 已经这样做了。
  • 减弱动效时进退场直接完成。