HextaUI

Drawer

任意の端からスライドインし、指に追従するパネルです。スナップポイント、実際に使えるハンドル、重なっていく入れ子のドロワーに対応します。

"use client"

import * as React from "react"
import { IconMinus, IconPlus } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"
import { NumberFlow } from "@/components/ui/number-flow"

export function DrawerDemo() {
  const [goal, setGoal] = React.useState(350)

  return (
    <Drawer>
      <DrawerTrigger render={<Button variant="outline" />}>
        Set daily goal
      </DrawerTrigger>
      <DrawerContent>
        <div className="mx-auto flex w-full max-w-sm flex-col">
          <DrawerHeader>
            <DrawerTitle>Move goal</DrawerTitle>
            <DrawerDescription>Set your daily activity goal.</DrawerDescription>
          </DrawerHeader>
          <div className="flex items-center justify-center gap-6 p-6">
            <Button
              variant="outline"
              size="icon"
              aria-label="Decrease goal"
              disabled={goal <= 200}
              onClick={() => setGoal(goal - 10)}
            >
              <IconMinus />
            </Button>
            <div className="flex min-w-32 flex-col items-center">
              <NumberFlow
                value={goal}
                className="text-6xl font-semibold tracking-tight"
              />
              <span className="text-xs text-muted-foreground uppercase">
                Calories / day
              </span>
            </div>
            <Button
              variant="outline"
              size="icon"
              aria-label="Increase goal"
              disabled={goal >= 600}
              onClick={() => setGoal(goal + 10)}
            >
              <IconPlus />
            </Button>
          </div>
          <DrawerFooter>
            <DrawerClose render={<Button />}>Save goal</DrawerClose>
            <DrawerClose render={<Button variant="outline" />}>
              Cancel
            </DrawerClose>
          </DrawerFooter>
        </div>
      </DrawerContent>
    </Drawer>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/drawer.json

コンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。

import {
  Drawer,
  DrawerBody,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"
<Drawer>
  <DrawerTrigger render={<Button variant="outline" />}>Open</DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Are you absolutely sure?</DrawerTitle>
      <DrawerDescription>This action cannot be undone.</DrawerDescription>
    </DrawerHeader>
    <DrawerBody>{/* content */}</DrawerBody>
    <DrawerFooter>
      <Button>Submit</Button>
      <DrawerClose render={<Button variant="outline" />}>Cancel</DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>
Drawer
├── DrawerTrigger
└── DrawerContent
    ├── DrawerHeader
    │   ├── DrawerTitle
    │   └── DrawerDescription
    ├── DrawerBody
    └── DrawerFooter
        └── DrawerClose

方向

<Drawer /> に swipeDirection を設定して端を選びます。drawer はその端から開き、その端に向かってスワイプして戻ります。上下の drawer には、デフォルトでハンドルが表示されます。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

const directions = [
  { value: "up", label: "Top" },
  { value: "right", label: "Right" },
  { value: "down", label: "Bottom" },
  { value: "left", label: "Left" },
] as const

export function DrawerDirections() {
  return (
    <div className="flex flex-wrap justify-center gap-2">
      {directions.map(({ value, label }) => (
        <Drawer key={value} swipeDirection={value}>
          <DrawerTrigger render={<Button variant="outline" />}>
            {label}
          </DrawerTrigger>
          <DrawerContent>
            <DrawerHeader>
              <DrawerTitle>Swipe {value} to close</DrawerTitle>
              <DrawerDescription>
                The drawer follows your finger and keeps the momentum when you
                let go.
              </DrawerDescription>
            </DrawerHeader>
            <DrawerFooter>
              <DrawerClose render={<Button variant="outline" />}>
                Close
              </DrawerClose>
            </DrawerFooter>
          </DrawerContent>
        </Drawer>
      ))}
    </div>
  )
}

スナップポイント

snapPoints を渡すと、下部の drawer をあらかじめ決めた高さで止められます。0 から 1 の数値はビューポートに対する割合、それより大きい数値はピクセル、文字列は px または rem を受け付けます。表示される部分は常にコンテンツに収まるため、画面の下に隠れるものはありません。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerBody,
  DrawerContent,
  DrawerDescription,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

const snapPoints = ["20rem", 1]

const places = [
  "Blue Bottle Coffee",
  "Tartine Bakery",
  "Mission Dolores Park",
  "Ferry Building",
  "Golden Gate Park",
  "Lands End Trail",
  "Twin Peaks",
  "Coit Tower",
  "Alamo Square",
  "Baker Beach",
  "Crissy Field",
  "Japanese Tea Garden",
]

export function DrawerSnapPoints() {
  return (
    <Drawer snapPoints={snapPoints}>
      <DrawerTrigger render={<Button variant="outline" />}>
        Nearby places
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>Nearby places</DrawerTitle>
          <DrawerDescription>
            Drag up to see the full list, or down to close.
          </DrawerDescription>
        </DrawerHeader>
        <DrawerBody>
          <ul className="flex flex-col divide-y">
            {places.map((place) => (
              <li key={place} className="py-3 text-sm">
                {place}
              </li>
            ))}
          </ul>
        </DrawerBody>
      </DrawerContent>
    </Drawer>
  )
}

スクロール可能なコンテンツ

<DrawerBody /> は単独でスクロールするため、ヘッダーとフッターはその場に保たれます。スワイプは、本体が一番上までスクロールされて初めて開始します。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerBody,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

const sections = Array.from({ length: 12 }, (_, index) => index + 1)

export function DrawerScrollable() {
  return (
    <Drawer>
      <DrawerTrigger render={<Button variant="outline" />}>
        Terms of service
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>Terms of service</DrawerTitle>
          <DrawerDescription>Last updated October 2026.</DrawerDescription>
        </DrawerHeader>
        <DrawerBody>
          <div className="flex flex-col gap-4 text-sm text-muted-foreground">
            {sections.map((section) => (
              <p key={section}>
                {section}. By using the service you agree to these terms. We may
                update them from time to time, and we will let you know when
                something important changes. Keep your account details safe and
                tell us if you think someone else has access.
              </p>
            ))}
          </div>
        </DrawerBody>
        <DrawerFooter>
          <DrawerClose render={<Button />}>Accept</DrawerClose>
          <DrawerClose render={<Button variant="outline" />}>
            Decline
          </DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  )
}

フォームとキーボード

下部の drawer にテキスト入力欄がある場合は、<DrawerContent /> を <DrawerVirtualKeyboardProvider /> で囲みます。スマートフォンでは、フォーカスされたフィールドがソフトウェアキーボードの陰に隠れず、その上に表示されるようスクロールされます。ヘッダーとフッターを固定しておくために、フィールドは <DrawerBody /> に入れておきます。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerBody,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
  DrawerVirtualKeyboardProvider,
} from "@/components/ui/drawer"
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"

export function DrawerKeyboard() {
  return (
    <Drawer>
      <DrawerTrigger render={<Button variant="outline" />}>
        Delivery details
      </DrawerTrigger>
      <DrawerVirtualKeyboardProvider>
        <DrawerContent>
          <DrawerHeader>
            <DrawerTitle>Delivery details</DrawerTitle>
            <DrawerDescription>
              Tap a field on your phone. It stays above the keyboard.
            </DrawerDescription>
          </DrawerHeader>
          <DrawerBody>
            <FieldGroup>
              <Field>
                <FieldLabel>Name</FieldLabel>
                <Input name="name" autoComplete="name" />
              </Field>
              <Field>
                <FieldLabel>Phone</FieldLabel>
                <Input name="phone" type="tel" autoComplete="tel" />
              </Field>
              <Field>
                <FieldLabel>Street address</FieldLabel>
                <Input name="street" autoComplete="street-address" />
              </Field>
              <Field>
                <FieldLabel>Apartment</FieldLabel>
                <Input name="apartment" />
              </Field>
              <Field>
                <FieldLabel>City</FieldLabel>
                <Input name="city" autoComplete="address-level2" />
              </Field>
              <Field>
                <FieldLabel>Postal code</FieldLabel>
                <Input name="postal" autoComplete="postal-code" />
              </Field>
            </FieldGroup>
          </DrawerBody>
          <DrawerFooter>
            <DrawerClose render={<Button />}>Save address</DrawerClose>
          </DrawerFooter>
        </DrawerContent>
      </DrawerVirtualKeyboardProvider>
    </Drawer>
  )
}

入れ子

同じ端にある drawer から開いた drawer は、手前に積み重なります。後ろのものは縮小して上にのぞき、一番上のものをスワイプで閉じる指に追従します。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

export function DrawerNested() {
  return (
    <Drawer>
      <DrawerTrigger render={<Button variant="outline" />}>
        Choose a plan
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>Choose a plan</DrawerTitle>
          <DrawerDescription>
            Compare plans, then open the details of the one you like.
          </DrawerDescription>
        </DrawerHeader>
        <DrawerFooter>
          <Drawer>
            <DrawerTrigger render={<Button />}>Pro plan details</DrawerTrigger>
            <DrawerContent>
              <DrawerHeader>
                <DrawerTitle>Pro plan</DrawerTitle>
                <DrawerDescription>
                  The first drawer steps back behind this one.
                </DrawerDescription>
              </DrawerHeader>
              <DrawerFooter>
                <Drawer>
                  <DrawerTrigger render={<Button />}>Checkout</DrawerTrigger>
                  <DrawerContent>
                    <DrawerHeader>
                      <DrawerTitle>Checkout</DrawerTitle>
                      <DrawerDescription>
                        Swipe down to go back one step.
                      </DrawerDescription>
                    </DrawerHeader>
                    <DrawerFooter>
                      <DrawerClose render={<Button variant="outline" />}>
                        Back
                      </DrawerClose>
                    </DrawerFooter>
                  </DrawerContent>
                </Drawer>
                <DrawerClose render={<Button variant="outline" />}>
                  Back
                </DrawerClose>
              </DrawerFooter>
            </DrawerContent>
          </Drawer>
          <DrawerClose render={<Button variant="outline" />}>Close</DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  )
}

drawer からの確認

ダイアログ、alert dialog、シート、および別の端にある drawer は、積み重なるのではなく、上に重なります。drawer は奥に下がり、より薄い背景がそれを覆います。

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

export function DrawerConfirm() {
  return (
    <Drawer>
      <DrawerTrigger render={<Button variant="outline" />}>
        Photo options
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>IMG_2048.heic</DrawerTitle>
          <DrawerDescription>Taken on October 3, 2026.</DrawerDescription>
        </DrawerHeader>
        <DrawerFooter>
          <DrawerClose render={<Button variant="outline" />}>Share</DrawerClose>
          <AlertDialog>
            <AlertDialogTrigger render={<Button variant="destructive" />}>
              Delete photo
            </AlertDialogTrigger>
            <AlertDialogContent>
              <AlertDialogHeader>
                <AlertDialogTitle>Delete “IMG_2048.heic”?</AlertDialogTitle>
                <AlertDialogDescription>
                  It will be removed from all your devices.
                </AlertDialogDescription>
              </AlertDialogHeader>
              <AlertDialogFooter>
                <AlertDialogCancel>Cancel</AlertDialogCancel>
                <AlertDialogAction variant="destructive">
                  Delete
                </AlertDialogAction>
              </AlertDialogFooter>
            </AlertDialogContent>
          </AlertDialog>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  )
}

レスポンシブ

メディアクエリで swipeDirection を切り替えると、デスクトップではサイドパネル、スマートフォンではボトムシートにできます。

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

const query = "(min-width: 768px)"

function subscribe(onChange: () => void) {
  const media = window.matchMedia(query)
  media.addEventListener("change", onChange)
  return () => media.removeEventListener("change", onChange)
}

function useIsDesktop() {
  return React.useSyncExternalStore(
    subscribe,
    () => window.matchMedia(query).matches,
    () => false
  )
}

export function DrawerResponsive() {
  const isDesktop = useIsDesktop()

  return (
    <Drawer swipeDirection={isDesktop ? "right" : "down"}>
      <DrawerTrigger render={<Button variant="outline" />}>
        Notifications
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>Notifications</DrawerTitle>
          <DrawerDescription>
            A side panel on desktop and a bottom sheet on phones.
          </DrawerDescription>
        </DrawerHeader>
        <DrawerFooter>
          <DrawerClose render={<Button variant="outline" />}>Close</DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  )
}

非モーダル

modal={false} では背景がなく、ページはスクロールし続け、フォーカスは drawer の外に出られます。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

export function DrawerNonModal() {
  return (
    <Drawer modal={false} swipeDirection="right">
      <DrawerTrigger render={<Button variant="outline" />}>
        Open inspector
      </DrawerTrigger>
      <DrawerContent>
        <DrawerHeader>
          <DrawerTitle>Inspector</DrawerTitle>
          <DrawerDescription>
            The page stays scrollable and clickable while this is open.
          </DrawerDescription>
        </DrawerHeader>
        <DrawerFooter>
          <DrawerClose render={<Button variant="outline" />}>Close</DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  )
}

制御

open と onOpenChange を渡すと、トリガーなしでどこからでも開けます。

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
} from "@/components/ui/drawer"

export function DrawerControlled() {
  const [open, setOpen] = React.useState(false)

  return (
    <>
      <Button variant="outline" onClick={() => setOpen(true)}>
        Open from anywhere
      </Button>
      <Drawer open={open} onOpenChange={setOpen}>
        <DrawerContent>
          <DrawerHeader>
            <DrawerTitle>Controlled drawer</DrawerTitle>
            <DrawerDescription>
              Opened from a plain button, without a trigger.
            </DrawerDescription>
          </DrawerHeader>
          <DrawerFooter>
            <Button variant="outline" onClick={() => setOpen(false)}>
              Close
            </Button>
          </DrawerFooter>
        </DrawerContent>
      </Drawer>
    </>
  )
}

分離したトリガー

createDrawerHandle で、1 つの drawer を複数のトリガーで共有できます。各トリガーは payload を渡し、drawer は関数の子要素を通じてそれをレンダリングします。

"use client"

import { Button } from "@/components/ui/button"
import {
  createDrawerHandle,
  Drawer,
  DrawerBody,
  DrawerContent,
  DrawerDescription,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

const contacts = createDrawerHandle<{ name: string; email: string }>()

export function DrawerDetached() {
  return (
    <div className="flex flex-wrap justify-center gap-2">
      <DrawerTrigger
        handle={contacts}
        payload={{ name: "Olivia Martin", email: "[email protected]" }}
        render={<Button variant="outline" size="sm" />}
      >
        Olivia
      </DrawerTrigger>
      <DrawerTrigger
        handle={contacts}
        payload={{ name: "Jackson Lee", email: "[email protected]" }}
        render={<Button variant="outline" size="sm" />}
      >
        Jackson
      </DrawerTrigger>
      <Drawer handle={contacts}>
        {({ payload }) => (
          <DrawerContent>
            <DrawerHeader>
              <DrawerTitle>{payload?.name}</DrawerTitle>
              <DrawerDescription>{payload?.email}</DrawerDescription>
            </DrawerHeader>
            <DrawerBody>
              <p className="text-sm text-muted-foreground">
                One drawer, opened by either trigger.
              </p>
            </DrawerBody>
          </DrawerContent>
        )}
      </Drawer>
    </div>
  )
}

右から左

<DrawerContent /> に dir="rtl" を渡すと、コンテンツが反転します。swipeDirection は物理的な端を指すため、"left" は左のまま、ハンドルは内側の端に残ります。

import { Button } from "@/components/ui/button"
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer"

export function DrawerRtl() {
  return (
    <div dir="rtl" className="flex flex-wrap justify-center gap-2">
      <Drawer>
        <DrawerTrigger render={<Button variant="outline" />}>
          من الأسفل
        </DrawerTrigger>
        <DrawerContent dir="rtl">
          <DrawerHeader>
            <DrawerTitle>تعديل الملف الشخصي</DrawerTitle>
            <DrawerDescription>
              يتم حفظ التغييرات عند النقر على حفظ.
            </DrawerDescription>
          </DrawerHeader>
          <DrawerFooter>
            <DrawerClose render={<Button />}>حفظ</DrawerClose>
            <DrawerClose render={<Button variant="outline" />}>
              إلغاء
            </DrawerClose>
          </DrawerFooter>
        </DrawerContent>
      </Drawer>
      <Drawer swipeDirection="left" showSwipeHandle>
        <DrawerTrigger render={<Button variant="outline" />}>
          من اليسار
        </DrawerTrigger>
        <DrawerContent dir="rtl">
          <DrawerHeader>
            <DrawerTitle>القائمة</DrawerTitle>
            <DrawerDescription>اسحب إلى اليسار للإغلاق.</DrawerDescription>
          </DrawerHeader>
          <DrawerFooter>
            <DrawerClose render={<Button variant="outline" />}>
              إغلاق
            </DrawerClose>
          </DrawerFooter>
        </DrawerContent>
      </Drawer>
    </div>
  )
}
キーアクション
EnterSpaceトリガーでは、drawer を開き、その内側にフォーカスを移動します。
TabShift + Tabフォーカス可能な要素の間を移動します。モーダルな drawer では、フォーカスは内側にとどまります。
Esc最上位の drawer を閉じ、そのトリガーにフォーカスを戻します。
  • drawer はダイアログです。<DrawerTitle /> がラベルを付け、<DrawerDescription /> が説明を補うため、必ずタイトルを含めてください。
  • スワイプだけが閉じる手段になることはありません。Escape、背景、<DrawerClose /> ボタンでも閉じます。
  • ハンドルは装飾であり、支援技術からは隠されます。マウスでは、drawer をドラッグせずに内側のテキストを選択できます。
  • モーションの低減が有効な場合、drawer はスライドではなくフェードで表示・非表示になります。ドラッグは引き続きポインターに追従します。

Base UI の drawer をベースにしています。各パーツは、ラップしているプリミティブの props を受け付けます。

プロパティ型デフォルト
swipeDirection開く端と、閉じるスワイプの方向。
"up" | "down" | "left" | "right""down"
showSwipeHandleハンドルを表示します。デフォルトは、上下では true、左右では false です。
boolean–
snapPoints縦向きの drawer が止まれる高さ。0〜1 はビューポートに対する割合、1 より大きい値はピクセル、文字列は px または rem を受け付けます。
(number | string)[]–
snapPoint
number | string | null–
defaultSnapPoint
number | string | null–
onSnapPointChange
(snapPoint, details) => void–
defaultOpen
booleanfalse
open
boolean–
onOpenChange
(open: boolean, details) => void–
onOpenChangeComplete開閉アニメーションの終了後に呼ばれます。
(open: boolean) => void–
modaltrue のときだけ、背景をレンダリングします。
boolean | "trap-focus"true
disablePointerDismissal背景がクリックされても開いたままにします。
booleanfalse
handle
DrawerHandle<Payload>–
children
ReactNode | ({ payload }) => ReactNode–
プロパティ型デフォルト
handle
DrawerHandle<Payload>–
payload
Payload–
render
ReactElement | (props, state) => ReactElement<button>
属性説明
data-slot="drawer-trigger"CSSでトリガーを指定します。
data-popup-opendrawer が開いている間、付与されます。

ポータル、背景、ビューポート、ポップアップに加えて、ハンドルをレンダリングします。縦向きの drawer は、ビューポートの高さから 4rem を引いた値までコンテンツに合わせます。サイドの drawer は幅 75% で、sm ブレークポイントからは最大 24rem です。h-* や w-* で上書きするか、data-[swipe-axis=y]: で 1 つの軸に限定します。

プロパティ型デフォルト
initialFocus
boolean | RefObject | (type) => HTMLElement | boolean–
finalFocus
boolean | RefObject | (type) => HTMLElement | boolean–
className
string | (state) => string–
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="drawer-popup"drawer のパネル。
data-slot="drawer-content"children を囲む内側のラッパー。他にスクロールするものがない場合にスクロールします。
data-swipe-directionup、right、down、left のいずれか。
data-swipe-axisx または y。
data-opendrawer が開いている間、付与されます。
data-starting-style表示アニメーションの間存在します。
data-ending-style非表示アニメーションの間存在します。
data-swipingドラッグされている間、付与されます。
data-snap-pointsdrawer にスナップポイントがあるときに付与されます。
data-expanded全高のスナップポイントで付与されます。
data-nested-drawer-open別の drawer が上で開いている間、付与されます。
data-stack同じ端にある別の drawer が上に積まれている間、付与されます。
--drawer-insetdrawer をビューポートの端から浮かせます。デフォルトは 0px です。
--drawer-bleed-background端を越えてドラッグしたときに現れる領域を塗ります。デフォルトはポップオーバーの色です。
--drawer-swipe-movement-x水平方向のドラッグ距離。-y の変数もあります。
--drawer-snap-point-offset現在のスナップポイントが上端からどれだけ下にあるか。
--nested-drawers上に開いている drawer の数。

modal が true のとき、<DrawerContent /> によってレンダリングされます。スワイプに合わせてフェードし、スナップポイントがある場合は少なくとも半分は表示されたままです。シートや別の端にある drawer の上に重なった drawer では、より薄い背景になります。

属性説明
data-slot="drawer-overlay"バックドロップ。
data-nested重なった drawer の、より薄い背景に付与されます。
--drawer-overlay-min-opacityスワイプ中にフェードする最小の不透明度。0、スナップポイントがある場合は 0.5。

showSwipeHandle がオンのとき、<DrawerContent /> によって内側の端にレンダリングされます。drawer 全体をドラッグできるため、ハンドルは視覚的な手がかりです。

属性説明
data-slot="drawer-swipe-handle"ハンドル。

drawer のレイアウトを構成するプレーンな <div> 要素。ヘッダーは小さい画面の縦向きの drawer でテキストを中央揃えにし、本体はスクロールして残りの空間を占め、フッターはアクションを縦に積みます。

属性説明
data-slot="drawer-header"タイトルと説明。
data-slot="drawer-body"スクロール可能なコンテンツ。
data-slot="drawer-footer"アクション。
プロパティ型デフォルト
render
ReactElement | (props, state) => ReactElement<h2>
属性説明
data-slot="drawer-title"drawer にラベルを付けます。
プロパティ型デフォルト
render
ReactElement | (props, state) => ReactElement<p>
属性説明
data-slot="drawer-description"drawer を説明します。

要素をレンダリングしません。<Drawer /> の内側で、<DrawerContent /> を囲むように配置します。ソフトウェアキーボードが開いている間、drawer のスクロールコンテナの下に余白を追加し、フォーカスされたフィールドを表示位置までスクロールし、iOS ではフィールドのタップでキーボードが開くようにします。これがない drawer には影響しません。

プロパティ型デフォルト
children
ReactNode–
属性説明
--drawer-keyboard-insetキーボードが開いている間、ビューポートに設定されます: キーボードがページと重なっている量です。0px のフォールバックとともに使います。
プロパティ型デフォルト
render
ReactElement | (props, state) => ReactElement<button>
属性説明
data-slot="drawer-close"押すと drawer を閉じます。

createDrawerHandle<Payload>() は、別の場所にレンダリングされたトリガーと <Drawer /> をつなぐハンドルを返します。コンポーネントの外で一度だけ作成してください。

使用しているブロック

Drawer の上に構築されるブロック。