跳到主要内容

Drawer 抽屉Drawer

从屏幕一侧滑入的模态面板,用来放比对话框更长的内容:详情、多字段表单、窄屏上的导航。它盖住页面的一部分,人还看得见原来的上下文。

同一张悬浮卡片

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

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

结构件

抽屉本身只是一张贴边的卡片,里面用 FloatingHeader(标题、说明、关闭按钮)、FloatingBody(可滚动的内容区)、FloatingFooter(一排按钮)来搭。头尾固定,内容超出时只有中间滚动。

四个方向

placement 决定从哪一侧滑入,默认 right。进退场和所有悬浮卡片共用:303ms 用 spring-soft 落位(不冲出边距),160ms ease-in 退场。

尺寸

size 是主轴尺寸。左右抽屉是宽度:sm 280、md 360(默认)、lg 480;上下抽屉是高度:sm 240、md 360、lg 520。也可以给数字(px)或 CSS 长度。

头部图标与撑满的按钮

FloatingHeader 的 icon 在标题左边放一个色块图标;FloatingFooter 的 align 控制按钮的排法(end、start、between、stretch)。

关闭方式

默认 Esc、点遮罩、头部的关闭按钮都能关。dismissible={false} 时前两种失效,头部的关闭按钮也随之消失,只能走你提供的按钮。dragToDismiss 让头部变成拖拽把手,朝停靠的那一侧拖出去关闭。

接口

Drawer

属性类型默认值说明
placement'left' | 'right' | 'top' | 'bottom''right'从哪一侧滑入。
size'sm' | 'md' | 'lg' | number | string'md'主轴尺寸。左右是宽度 280 / 360 / 480;上下是高度 240 / 360 / 520。
modalbooleantrue模态:带遮罩、锁滚动、圈住焦点。需要非模态时优先用 Panel。
stretchbooleantrue是否在另一个方向上撑满;false 则按内容大小并居中。
dragToDismissbooleanfalse按住头部(或抓手)朝停靠的那一侧拖拽关闭。需要 dismissible。
role'dialog' | 'alertdialog' | 'complementary' | 'region''dialog'语义角色。
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 的标题和说明。

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" 加 aria-modal="true",名字和描述自动取自 FloatingHeader 的标题和说明。不用 FloatingHeader 时请自己给 aria-label。
  • 打开时焦点移进抽屉(initialFocus → data-autofocus → 卡片本身),Tab 被圈在里面循环;关闭后焦点回到打开它的元素。
  • Esc 或点遮罩关闭;头部的关闭按钮是带名字的图标按钮(默认“关闭”,可用 closeLabel 改)。
  • 内容区是原生滚动容器,键盘可以用方向键、空格、PageUp / PageDown 滚动。
  • 拖拽关闭只是指针上的捷径,键盘和读屏用户始终有 Esc 和关闭按钮;不要做成唯一的关闭方式。
  • 打开期间页面背景锁定滚动。减弱动效时滑入滑出直接完成。