HextaUI

Drawer

Ein Panel, das von jeder Kante hereingleitet und deinem Finger folgt, mit Snap-Punkten, einem funktionierenden Griff und verschachtelten Drawern, die sich stapeln.

"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

Fügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.

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

Richtungen

Setze swipeDirection auf <Drawer />, um den Rand zu wählen. Der Drawer öffnet sich von diesem Rand und wird zu ihm zurückgewischt. Obere und untere Drawer zeigen standardmäßig einen Griff.

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>
  )
}

Snap-Punkte

Übergib snapPoints, damit ein Bottom Drawer bei voreingestellten Höhen verharrt. Zahlen von 0 bis 1 sind Anteile des Viewports, größere Zahlen sind Pixel, und Strings nehmen px oder rem. Der sichtbare Teil passt immer zu seinem Inhalt, sodass nichts unterhalb des Bildschirms verschwindet.

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>
  )
}

Scrollbarer Inhalt

<DrawerBody /> scrollt für sich, sodass Header und Footer an Ort und Stelle bleiben. Das Wischen beginnt erst, wenn der Body wieder ganz nach oben gescrollt ist.

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>
  )
}

Formulare und die Tastatur

Umschließe <DrawerContent /> mit <DrawerVirtualKeyboardProvider />, wenn ein Bottom Drawer Textfelder enthält. Auf Smartphones scrollt das fokussierte Feld über der Software-Tastatur in den Sichtbereich, statt sich dahinter zu verstecken. Belasse die Felder in <DrawerBody />, damit Header und Footer stehen bleiben.

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>
  )
}

Verschachtelt

Ein Drawer, der aus einem Drawer am selben Rand geöffnet wird, legt sich darüber. Die dahinterliegenden schrumpfen, schauen oben hervor und folgen deinem Finger, während du den obersten wegwischst.

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>
  )
}

Bestätigen aus einem Drawer

Dialoge, Alert Dialogs, Sheets und Drawer an einem anderen Rand legen sich darüber, statt sich zu stapeln. Der Drawer tritt zurück, und ein hellerer Backdrop deckt ihn ab.

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>
  )
}

Responsive

Ändere swipeDirection mit einer Media Query, um auf dem Desktop ein Seitenpanel und auf Smartphones ein Bottom Sheet zu zeigen.

"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>
  )
}

Nicht modal

Mit modal={false} gibt es keinen Backdrop, die Seite scrollt weiter, und der Fokus kann den Drawer verlassen.

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>
  )
}

Kontrolliert

Übergib open und onOpenChange, um ihn von überall ohne Trigger zu öffnen.

"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>
    </>
  )
}

Losgelöste Trigger

Teile einen Drawer zwischen mehreren Triggern mit createDrawerHandle. Jeder Trigger übergibt ein payload, das der Drawer über ein Funktions-Kind rendert.

"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>
  )
}

Rechts nach links

Übergib dir="rtl" an <DrawerContent />, um seinen Inhalt zu spiegeln. swipeDirection benennt einen physischen Rand, sodass "left" links bleibt und der Griff am inneren Rand bleibt.

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>
  )
}
TasteAktion
EnterSpaceAm Trigger: öffnet den Drawer und setzt den Fokus hinein.
TabShift + TabWechselt zwischen fokussierbaren Elementen. Der Fokus bleibt in einem modalen Drawer.
EscSchließt den obersten Drawer und gibt den Fokus an seinen Trigger zurück.
  • Der Drawer ist ein Dialog. <DrawerTitle /> beschriftet ihn und <DrawerDescription /> beschreibt ihn, binde also immer einen Titel ein.
  • Wischen ist nie der einzige Ausweg: Escape, der Backdrop und ein <DrawerClose />-Button schließen ihn ebenfalls.
  • Der Griff ist dekorativ und für assistive Technologien verborgen. Mit der Maus lässt sich Text im Drawer markieren, ohne ihn zu ziehen.
  • Bei reduzierter Bewegung blendet der Drawer ein und aus, statt zu gleiten. Das Ziehen folgt weiterhin dem Zeiger.

Basiert auf dem Base UI Drawer. Jeder Teil akzeptiert die Props der Primitive, die er umschließt.

PropTypStandard
swipeDirectionDer Rand, von dem er sich öffnet, und die Richtung, die ihn schließt.
"up" | "down" | "left" | "right""down"
showSwipeHandleZeigt den Griff. Standardmäßig true für oben und unten, false für links und rechts.
boolean–
snapPointsHöhen, bei denen ein vertikaler Drawer verharren kann. 0–1 ist ein Anteil des Viewports, >1 sind Pixel, Strings nehmen px oder rem.
(number | string)[]–
snapPoint
number | string | null–
defaultSnapPoint
number | string | null–
onSnapPointChange
(snapPoint, details) => void–
defaultOpen
booleanfalse
open
boolean–
onOpenChange
(open: boolean, details) => void–
onOpenChangeCompleteWird aufgerufen, nachdem die Öffnen- oder Schließen-Animation endet.
(open: boolean) => void–
modalDer Backdrop wird nur gerendert, wenn true.
boolean | "trap-focus"true
disablePointerDismissalOffen halten, wenn auf den Backdrop geklickt wird.
booleanfalse
handle
DrawerHandle<Payload>–
children
ReactNode | ({ payload }) => ReactNode–
PropTypStandard
handle
DrawerHandle<Payload>–
payload
Payload–
render
ReactElement | (props, state) => ReactElement<button>
AttributBeschreibung
data-slot="drawer-trigger"Den Trigger in CSS ansprechen.
data-popup-openVorhanden, solange sein Drawer geöffnet ist.

Rendert Portal, Backdrop, Viewport und Popup sowie den Griff. Vertikale Drawer passen sich ihrem Inhalt an, bis zur Viewport-Höhe minus 4 rem. Seitliche Drawer sind 75 % breit, ab dem Breakpoint sm bis zu 24 rem. Überschreibe mit h-* oder w-* oder begrenze auf eine Achse mit data-[swipe-axis=y]:.

PropTypStandard
initialFocus
boolean | RefObject | (type) => HTMLElement | boolean–
finalFocus
boolean | RefObject | (type) => HTMLElement | boolean–
className
string | (state) => string–
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="drawer-popup"Das Drawer-Panel.
data-slot="drawer-content"Der innere Wrapper um deine Kinder. Er scrollt, wenn sonst nichts scrollt.
data-swipe-directionup, right, down oder left.
data-swipe-axisx oder y.
data-openVorhanden, solange der Drawer geöffnet ist.
data-starting-styleVorhanden, während es einanimiert.
data-ending-styleVorhanden, während es ausanimiert.
data-swipingVorhanden, solange er gezogen wird.
data-snap-pointsVorhanden, wenn der Drawer Snap-Punkte hat.
data-expandedVorhanden am Snap-Punkt mit voller Höhe.
data-nested-drawer-openVorhanden, solange ein anderer Drawer darüber geöffnet ist.
data-stackVorhanden, solange ein Drawer am selben Rand darüber gestapelt ist.
--drawer-insetLässt den Drawer von den Rändern des Viewports abgesetzt schweben. Standardmäßig 0px.
--drawer-bleed-backgroundFüllt den Bereich, der beim Ziehen über den Rand hinaus freigelegt wird. Standardmäßig die Popover-Farbe.
--drawer-swipe-movement-xHorizontale Ziehstrecke. Es gibt auch eine -y-Variable.
--drawer-snap-point-offsetWie weit der aktuelle Snap-Punkt unterhalb der Oberkante liegt.
--nested-drawersWie viele Drawer darüber geöffnet sind.

Wird von <DrawerContent /> gerendert, wenn modal true ist. Er blendet beim Wischen aus und bleibt bei Snap-Punkten mindestens zur Hälfte sichtbar. Ein Drawer über einem Sheet oder einem Drawer an einem anderen Rand erhält einen helleren Backdrop.

AttributBeschreibung
data-slot="drawer-overlay"Der Hintergrund.
data-nestedVorhanden an helleren Backdrops von übereinanderliegenden Drawern.
--drawer-overlay-min-opacityDie niedrigste Deckkraft, auf die er beim Wischen ausblendet. 0, oder 0,5 mit Snap-Punkten.

Wird von <DrawerContent /> am inneren Rand gerendert, wenn showSwipeHandle aktiv ist. Der ganze Drawer lässt sich ziehen, der Griff ist also ein visueller Hinweis.

AttributBeschreibung
data-slot="drawer-swipe-handle"Der Griff.

Einfache <div>-Elemente, die den Drawer anordnen. Der Header zentriert seinen Text in vertikalen Drawern auf kleinen Bildschirmen, der Body scrollt und nimmt den verbleibenden Platz ein, und der Footer stapelt seine Aktionen.

AttributBeschreibung
data-slot="drawer-header"Titel und Beschreibung.
data-slot="drawer-body"Scrollbarer Inhalt.
data-slot="drawer-footer"Aktionen.
PropTypStandard
render
ReactElement | (props, state) => ReactElement<h2>
AttributBeschreibung
data-slot="drawer-title"Beschriftet den Drawer.
PropTypStandard
render
ReactElement | (props, state) => ReactElement<p>
AttributBeschreibung
data-slot="drawer-description"Beschreibt den Drawer.

Rendert kein Element. Setze es in <Drawer />, um <DrawerContent />. Solange die Software-Tastatur geöffnet ist, schafft es Platz unter dem Scroll-Container des Drawers, scrollt das fokussierte Feld in den Sichtbereich und sorgt dafür, dass Tippen auf Felder unter iOS die Tastatur öffnet. Drawer ohne es bleiben unberührt.

PropTypStandard
children
ReactNode–
AttributBeschreibung
--drawer-keyboard-insetWird auf den Viewport gesetzt, solange die Tastatur geöffnet ist: wie viel davon die Seite überlappt. Verwende es mit einem Fallback von 0px.
PropTypStandard
render
ReactElement | (props, state) => ReactElement<button>
AttributBeschreibung
data-slot="drawer-close"Schließt den Drawer beim Drücken.

createDrawerHandle<Payload>() gibt ein Handle zurück, das einen <Drawer /> mit an anderer Stelle gerenderten Triggern verbindet. Erstelle es einmal, außerhalb deiner Komponente.

In Blocks verwendet

Blocks, die auf Drawer aufbauen.