Pro组件、模板与 AI 工具
HeroUI
27.7k

Sheet 面板新

支持原生滚动吸附、分段展开和嵌套的滑动面板

用法

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

组件结构

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

export default () => (
  <Sheet>
    <Sheet.Trigger>
      <Button>打开面板</Button>
    </Sheet.Trigger>
    <Sheet.Backdrop>
      <Sheet.Content>
        <Sheet.Dialog>
          <Sheet.Handle />
          <Sheet.CloseTrigger />
          <Sheet.Header>
            <Sheet.Heading>详情</Sheet.Heading>
          </Sheet.Header>
          <Sheet.Body>面板内容</Sheet.Body>
          <Sheet.Footer>
            <Sheet.Close>
              <Button>完成</Button>
            </Sheet.Close>
          </Sheet.Footer>
        </Sheet.Dialog>
      </Sheet.Content>
    </Sheet.Backdrop>
  </Sheet>
);

Sheet.Root 是 Sheet 的别名。将 Sheet.Trigger 直接放在根组件内,并包裹一个可按压元素(如 Button)。通过 Sheet.Heading、aria-label 或 aria-labelledby 为对话框提供无障碍名称。使用 Sheet.Close、Sheet.CloseTrigger 或带有 slot="close" 的按钮支持键盘关闭;拖动手柄对辅助技术隐藏。

示例

位置

根组件的 placement 支持 bottom(默认)、top、left 和 right。

吸附点

数字表示像素,而不是比例。字符串表示 CSS 长度;百分比相对于面板尺寸。面板初始停留在第一个吸附点,完整展开位置始终隐式存在。末尾的 1、"1" 或 "100%" 会被忽略。其他数字仍以像素为单位。

连续吸附点

一次滑动可以跨越多个吸附点。完全展开位置隐式存在,无需额外的连续吸附属性。

吸附点(遮罩渐显)

经过部分展开的吸附点时,背景保持透明;越过最后一个吸附点并继续展开时,背景逐渐显现。此行为由 React Aria 管理,不支持 fadeFromIndex。

遮罩变体

不可关闭

isDismissable={false} 阻止点击外部、Escape 和滑动关闭。显式关闭按钮仍然可用。

可滚动内容

在部分展开时,滑动会展开面板;完全展开后,Sheet.Body 才滚动内部内容。Sheet.Handle 也支持鼠标拖动。

搭配表单

在 Sheet.Body 内组合表单字段。在面板表面使用次要样式的输入框。

悬浮面板

isDetached 在屏幕边缘与面板之间添加间距,并将所有角设为圆角。

受控状态

组合使用 isOpen 和 onOpenChange,或用 defaultOpen 设置非受控初始状态。受控面板可以省略 Sheet.Trigger。

拖动手柄

手柄提供可见的拖动提示,并支持指针拖动。面板完全展开前,触摸滑动也可作用于面板本身,并不限于手柄区域。

嵌套面板

将 Sheet.NestedRoot 放在另一个面板内。React Aria 管理堆叠和焦点恢复,只有最底层面板使页面背景变暗。

职业选择器

在初始吸附点为 355px 的面板中组合搜索框和虚拟列表。选择职业后更新所选值并关闭面板。

自定义样式

通过各部分的 className 或 @layer components 中的 sheet__* BEM 类自定义样式。保留 React Aria 的滚动定位,不要叠加独立的位移动画。

Tailwind CSS

通过 className 为各部分添加 Tailwind CSS 工具类。

<Sheet>
  <Sheet.Trigger>
    <Button variant="secondary">打开面板</Button>
  </Sheet.Trigger>
  <Sheet.Backdrop>
    <Sheet.Content className="mx-auto max-w-lg">
      <Sheet.Dialog className="rounded-t-3xl border border-border">
        <Sheet.Handle />
        <Sheet.CloseTrigger aria-label="关闭面板" />
        <Sheet.Header className="text-center">
          <Sheet.Heading>详情</Sheet.Heading>
        </Sheet.Header>
        <Sheet.Body className="px-6 pb-6">面板内容</Sheet.Body>
      </Sheet.Dialog>
    </Sheet.Content>
  </Sheet.Backdrop>
</Sheet>

全局 CSS

使用 @layer components 自定义 Sheet 的 BEM 类。

@layer components {
  .sheet__dialog {
    @apply border border-border;
  }

  .sheet__header {
    @apply text-center;
  }

  .sheet__body {
    @apply px-6 pb-6;
  }
}

样式参考

HeroUI 使用 BEM 命名规范,使组件样式易于复用和自定义。

CSS 类

基础类

  • .sheet__overlay - 模态遮罩容器
  • .sheet__backdrop - 面板后方的背景遮罩
  • .sheet__content - 控制面板尺寸与堆叠的容器
  • .sheet__dialog - 对话框表面
  • .sheet__header - 头部区域
  • .sheet__heading - 对话框标题
  • .sheet__body - 完全展开后可滚动的内容区域
  • .sheet__footer - 底部操作区域
  • .sheet__handle - 可拖动的手柄区域
  • .sheet__handle-bar - 默认手柄指示条
  • .sheet__close-trigger - 关闭按钮

遮罩变体

  • .sheet__backdrop--opaque - 暗色遮罩(默认)
  • .sheet__backdrop--blur - 模糊背景遮罩
  • .sheet__backdrop--transparent - 透明背景遮罩

嵌套时,仅最底层面板显示背景遮罩。

位置变体

  • .sheet__content--bottom, .sheet__dialog--bottom - 底部(默认)
  • .sheet__content--top, .sheet__dialog--top - 顶部
  • .sheet__content--left, .sheet__dialog--left - 左侧
  • .sheet__content--right, .sheet__dialog--right - 右侧

交互状态

  • [data-focus-visible="true"] - 关闭按钮的键盘焦点;原生回退选择器为 :focus-visible:not([data-focused])
  • :hover, [data-hovered="true"] - 关闭按钮悬停
  • :disabled, [aria-disabled="true"] - 关闭按钮禁用
  • [data-dragging] - 正在拖动手柄
  • [data-expanded] - 面板完全展开,启用内容滚动
  • [data-has-descendants] - 存在已打开的嵌套面板
  • [data-detached] - 面板与边缘留有间距,并使用圆角
  • [data-snap-points] - 面板配置了部分展开吸附点
  • [data-entering], [data-exiting] - 打开与关闭的生命周期状态
  • [data-closed] - 保留的已关闭遮罩,禁用指针交互

数据属性

DOM 部分提供以下 data-slot:sheet-overlay、sheet-backdrop、sheet-content、sheet-dialog、sheet-header、sheet-heading、sheet-body、sheet-footer、sheet-handle、sheet-handle-bar 和 sheet-close-trigger。根组件、Trigger 和 Close 不添加 DOM 元素。

Sheet.Content 还提供 data-placement、data-detached 和 data-snap-points。React Aria 在相应部分提供 data-position、data-expanded、data-stack-index、data-has-descendants、data-entering 和 data-exiting。

API 参考

Sheet / Sheet.Root / Sheet.NestedRoot

属性类型默认值说明
childrenReactNode—组合部分。
isOpenboolean—受控打开状态。
defaultOpenbooleanfalse非受控初始状态。
onOpenChange(open: boolean) => void—请求打开或关闭时调用。
onClose() => void—请求关闭时调用。
onAnimationEnd(open: boolean) => void—进入或退出结束后调用。
placement"bottom" | "top" | "left" | "right""bottom"屏幕的物理边缘。
isDismissablebooleantrue允许外部交互、Escape 和滑动关闭。
isDetachedbooleanfalse面板与屏幕边缘保持间距。
snapPoints(number | string)[]—部分展开的吸附位置;完整展开位置隐式存在。

Sheet.NestedRoot 必须在父 Sheet 内使用。根组件的 isNested 为内部标记;嵌套时使用 NestedRoot。

Sheet.Trigger

属性类型默认值说明
childrenReactElement—一个可按压的子元素,如 Button。直接放在 Sheet 内。

Sheet.Close

属性类型默认值说明
childrenReactElement—一个可按压的子元素;其 onPress 回调与关闭操作组合执行。

Sheet.Backdrop

属性类型默认值说明
childrenReactNode—要渲染的内容。
classNamestring—CSS 类名。
variant"opaque" | "blur" | "transparent""opaque"遮罩外观。
isExitingboolean—关闭后保留内容,直到清除此标记。

其他属性继承自 React Aria SheetOverlay,但不包含由根组件控制的状态、位置、吸附点和 style。关闭仍会释放模态焦点限制和页面滚动锁定。不再需要保留内容时,请清除 isExiting。

Sheet.Content

属性类型默认值说明
childrenReactNode | ((values: SheetRenderProps) => ReactNode)—内容或接收 React Aria 面板状态的函数。
classNamestring—CSS 类名。

其余属性继承自 React Aria Sheet。HeroUI 管理堆叠动画与过度滚动留白;stackAnimation 和 overscrollPadding 无法通过此组件覆盖。

Sheet.Dialog

属性类型默认值说明
childrenReactNode—要渲染的内容。
classNamestring—CSS 类名。
role"dialog" | "alertdialog""dialog"对话框无障碍角色。
aria-labelstring—没有可见标题时的无障碍名称。
aria-labelledbystring—为对话框提供名称的元素 ID。
aria-describedbystring—描述对话框的元素 ID。

其余属性与 ref 继承自 React Aria SheetContent。

Sheet.Header

属性类型默认值说明
childrenReactNode—头部内容。
classNamestring—CSS 类名。

支持标准 div 属性、事件处理函数和 ref。

Sheet.Heading

属性类型默认值说明
childrenReactNode—对话框标题。
classNamestring—CSS 类名。
slotstring"title"将标题关联到对话框。

其余属性与 ref 继承自 React Aria Heading。

Sheet.Body

属性类型默认值说明
childrenReactNode—可滚动的主体内容。
classNamestring—CSS 类名。

支持标准 div 属性、事件处理函数和 ref。

Sheet.Footer

属性类型默认值说明
childrenReactNode—底部操作。
classNamestring—CSS 类名。

支持标准 div 属性、事件处理函数和 ref。

Sheet.Handle

属性类型默认值说明
childrenReactNode—自定义手柄;省略时渲染默认指示条。
classNamestring—CSS 类名。

支持标准 div 属性、事件处理函数和 ref。

Sheet.CloseTrigger

属性类型默认值说明
childrenReactNode | ((values: ButtonRenderProps) => ReactNode)—自定义内容;默认显示关闭图标。
classNamestring—CSS 类名。
isDisabledbooleanfalse禁用关闭按钮。
aria-labelstring"Close"无障碍名称;按需提供本地化文本。
onPress(event: PressEvent) => void—与面板关闭操作一起调用。

其余属性与 ref 继承自 CloseButton。

命名导出包括 SheetRoot、SheetTrigger 等各部分、对应的属性类型、SheetProps、SheetNestedRootProps、sheetVariants 和 SheetVariants。组合属性类型使用索引访问,例如 Sheet["Props"] 和 Sheet["ContentProps"]。

Sheet 与 Drawer

Sheet 使用 React Aria 原生滚动手势,支持部分吸附位置和嵌套堆叠。Drawer 保留原有 API 和行为;新增 Sheet 不会迁移或弃用 Drawer。

无障碍

  • 无障碍名称:使用 Sheet.Heading、aria-label 或 aria-labelledby 为对话框提供名称。
  • 焦点管理:打开时将焦点移入面板并限制在当前模态面板内。关闭后,焦点返回触发器;关闭嵌套面板后返回父面板。
  • 键盘:使用 Tab 和 Shift+Tab 在控件间移动;允许关闭时,Escape 关闭面板。
  • 关闭控件:Sheet.Close 和 Sheet.CloseTrigger 支持键盘操作,即使 isDismissable={false} 也可关闭面板。
  • 滚动锁定:模态面板打开时锁定页面滚动。完全展开后,Sheet.Body 可滚动。保留的已关闭内容不会继续锁定页面。
  • 拖动手柄:手柄对辅助技术隐藏,不可通过键盘拖动。请提供可访问的关闭控件,不要仅依赖滑动手势。

相关组件

本页目录