ProComponents, templates & AI tooling
HeroUI
27.7k

Drawer 抽屉

用于补充内容与操作的侧滑面板。

引入

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

用法

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

export function Basic() {
  return (
    <Drawer>

组件结构

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

export default () => (
  <Drawer>
    <Button>Open Drawer</Button>
    <Drawer.Backdrop>
      <Drawer.Content>
        <Drawer.Dialog>
          <Drawer.Handle /> {/* Optional: Drag handle */}
          <Drawer.CloseTrigger /> {/* Optional: Close button */}
          <Drawer.Header>
            <Drawer.Heading />
          </Drawer.Header>
          <Drawer.Body />
          <Drawer.Footer />
        </Drawer.Dialog>
      </Drawer.Content>
    </Drawer.Backdrop>
  </Drawer>
);

位置

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

const PLACEMENT_LABELS = {
  bottom: "底部",
  left: "左侧",

遮罩变体

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

const VARIANT_LABELS = {
  blur: "模糊",
  opaque: "不透明",

不可关闭

Drawer.Backdrop 上设置 isDismissable={false},可阻止通过点击外部或拖动关闭。用户必须与抽屉内的操作按钮交互才能关闭。

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

export function NonDismissable() {
  return (
    <Drawer>

可滚动内容

Drawer.Body 会使用原生滚动处理溢出。为避免与滚动冲突,拖拽关闭不会在 body 区域生效。

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

export function ScrollableContent() {
  return (
    <Drawer>

受控状态

配合 React.useState()

使用 React 的 useState 管理抽屉开关,适合简单场景。

状态: 关闭

配合 useOverlayState()

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

状态: 关闭

"use client";

import {Button, Drawer, useOverlayState} from "@heroui/react";
import React from "react";

带表单

import {Button, Drawer, Input, Label, TextField} from "@heroui/react";

export function WithForm() {
  return (
    <Drawer>

导航抽屉

import type {ComponentType, SVGProps} from "react";

import {Bars, Bell, Envelope, Gear, House, Magnifier, Person} from "@gravity-ui/icons";
import {Button, Drawer} from "@heroui/react";

样式

传入 Tailwind CSS 类

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

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

自定义组件类

若要自定义 Drawer 组件类,可以使用 @layer components 指令。


了解更多

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

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

  .drawer__header {
    @apply text-center;
  }

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

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

CSS 类

Drawer 组件使用以下 CSS 类(查看源码样式):

基础类

  • .drawer__trigger - 打开 Drawer 的触发元素
  • .drawer__backdrop - Drawer 背后的遮罩
  • .drawer__content - Drawer 面板的定位包裹层
  • .drawer__dialog - Drawer 面板本体
  • .drawer__header - 表头区域
  • .drawer__heading - 主标题文本
  • .drawer__body - 可滚动主体内容区域
  • .drawer__footer - 表底操作区域
  • .drawer__handle - 视觉拖拽把手
  • .drawer__close-trigger - 关闭按钮元素

遮罩变体

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

位置变体

  • .drawer__content--bottom - 自底边上滑(默认)
  • .drawer__content--top - 自顶边下滑
  • .drawer__content--left - 自左侧滑入
  • .drawer__content--right - 自右侧滑入

对话框变体

  • .drawer__dialog--top - 自顶边下滑
  • .drawer__dialog--bottom - 自底边上滑
  • .drawer__dialog--left - 自左侧滑入
  • .drawer__dialog--right - 自右侧滑入

交互状态

该组件支持以下交互状态:

  • 聚焦:focus-visible[data-focus-visible="true"] — 应用于触发器与关闭按钮
  • 悬停:hover[data-hovered="true"] — 关闭按钮悬停时应用
  • 激活:active[data-pressed="true"] — 触发器与关闭按钮被按压时应用
  • 进入[data-entering] — Drawer 打开动画期间应用
  • 离开[data-exiting] — Drawer 关闭动画期间应用
  • 位置[data-placement="*"] — 根据 Drawer 位置应用(top、bottom、left、right)

API 参考

Drawer

PropType默认值描述
childrenReactNode-触发器与遮罩子元素。
stateUseOverlayStateReturn-受控的叠加层状态。

Drawer.Trigger

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

Drawer.Backdrop

PropType默认值描述
variant"opaque" | "blur" | "transparent""opaque"遮罩叠加样式。
isDismissablebooleantrue点击遮罩是否关闭。
isKeyboardDismissDisabledbooleanfalse是否禁用 ESC 关闭。
isOpenboolean-受控打开状态。
onOpenChange(isOpen: boolean) => void-打开状态变化时的事件处理函数。
classNamestring | (values) => string-遮罩 CSS 类。

Drawer.Content

PropType默认值描述
placement"top" | "bottom" | "left" | "right""bottom"Drawer 从哪一侧滑入。
classNamestring | (values) => string-Content CSS 类。

Drawer.Dialog

PropType默认值描述
childrenReactNode-对话框内容。
classNamestring-CSS 类。
rolestring"dialog"ARIA role。
aria-labelstring-无障碍标签。
aria-labelledbystring-标签元素 ID。

Drawer.Header

PropType默认值描述
childrenReactNode-表头内容。
classNamestring-CSS 类。

Drawer.Heading

PropType默认值描述
childrenReactNode-标题文本。
classNamestring-CSS 类。

Drawer.Body

PropType默认值描述
childrenReactNode-主体内容。
classNamestring-CSS 类。

Drawer.Footer

PropType默认值描述
childrenReactNode-表底内容。
classNamestring-CSS 类。

Drawer.Handle

PropType默认值描述
classNamestring-CSS 类。

Drawer.CloseTrigger

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

useOverlayState Hook

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

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

state.isOpen; // Current state
state.open(); // Open drawer
state.close(); // Close drawer
state.toggle(); // Toggle state
state.setOpen(); // Set state directly

无障碍

实现 WAI-ARIA Dialog 模式

  • 焦点陷阱:打开时将焦点锁定在 Drawer 内
  • 键盘:可关闭时 ESC 关闭,Tab 在可聚焦元素间循环
  • 屏幕阅读器:通过 React Aria 提供合适的 ARIA 属性
  • 滚动锁定:打开时禁用 body 滚动
  • 拖拽关闭:支持在把手、表头与表底等区域的指针拖拽手势

本页目录