Drawer
Ein Panel, das von jeder Kante hereingleitet und deinem Finger folgt, mit Snap-Punkten, einem funktionierenden Griff und verschachtelten Drawern, die sich stapeln.
pnpm dlx shadcn@latest add https://hextaui.com/r/drawer.jsonFügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.
Füge die Theme-Tokens zu deinem globalen CSS hinzu, falls du das noch nicht getan hast.
Installiere die Abhängigkeiten.
pnpm add @base-ui/react @tabler/icons-react cnKopiere den folgenden Code und füge ihn in dein Projekt ein.
components/ui/drawer.tsx components/ui/sheet.tsx components/ui/button.tsx Passe die Importpfade an dein Projekt-Setup an.
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.
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.
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.
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.
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.
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.
Responsive
Ändere swipeDirection mit einer Media Query, um auf dem Desktop ein Seitenpanel und auf Smartphones ein Bottom Sheet zu zeigen.
Nicht modal
Mit modal={false} gibt es keinen Backdrop, die Seite scrollt weiter, und der Fokus kann den Drawer verlassen.
Kontrolliert
Übergib open und onOpenChange, um ihn von überall ohne Trigger zu öffnen.
Losgelöste Trigger
Teile einen Drawer zwischen mehreren Triggern mit createDrawerHandle. Jeder Trigger übergibt ein payload, das der Drawer über ein Funktions-Kind rendert.
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.
| Taste | Aktion |
|---|---|
| EnterSpace | Am Trigger: öffnet den Drawer und setzt den Fokus hinein. |
| TabShift + Tab | Wechselt zwischen fokussierbaren Elementen. Der Fokus bleibt in einem modalen Drawer. |
| Esc | Schließ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.
| Prop | Typ | Standard |
|---|---|---|
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 | boolean | false |
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. | boolean | false |
handle | DrawerHandle<Payload> | – |
children | ReactNode | ({ payload }) => ReactNode | – |
| Prop | Typ | Standard |
|---|---|---|
handle | DrawerHandle<Payload> | – |
payload | Payload | – |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribut | Beschreibung |
|---|---|
data-slot="drawer-trigger" | Den Trigger in CSS ansprechen. |
data-popup-open | Vorhanden, 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]:.
| Prop | Typ | Standard |
|---|---|---|
initialFocus | boolean | RefObject | (type) => HTMLElement | boolean | – |
finalFocus | boolean | RefObject | (type) => HTMLElement | boolean | – |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
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-direction | up, right, down oder left. |
data-swipe-axis | x oder y. |
data-open | Vorhanden, solange der Drawer geöffnet ist. |
data-starting-style | Vorhanden, während es einanimiert. |
data-ending-style | Vorhanden, während es ausanimiert. |
data-swiping | Vorhanden, solange er gezogen wird. |
data-snap-points | Vorhanden, wenn der Drawer Snap-Punkte hat. |
data-expanded | Vorhanden am Snap-Punkt mit voller Höhe. |
data-nested-drawer-open | Vorhanden, solange ein anderer Drawer darüber geöffnet ist. |
data-stack | Vorhanden, solange ein Drawer am selben Rand darüber gestapelt ist. |
--drawer-inset | Lässt den Drawer von den Rändern des Viewports abgesetzt schweben. Standardmäßig 0px. |
--drawer-bleed-background | Füllt den Bereich, der beim Ziehen über den Rand hinaus freigelegt wird. Standardmäßig die Popover-Farbe. |
--drawer-swipe-movement-x | Horizontale Ziehstrecke. Es gibt auch eine -y-Variable. |
--drawer-snap-point-offset | Wie weit der aktuelle Snap-Punkt unterhalb der Oberkante liegt. |
--nested-drawers | Wie 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.
| Attribut | Beschreibung |
|---|---|
data-slot="drawer-overlay" | Der Hintergrund. |
data-nested | Vorhanden an helleren Backdrops von übereinanderliegenden Drawern. |
--drawer-overlay-min-opacity | Die 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.
| Attribut | Beschreibung |
|---|---|
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.
| Attribut | Beschreibung |
|---|---|
data-slot="drawer-header" | Titel und Beschreibung. |
data-slot="drawer-body" | Scrollbarer Inhalt. |
data-slot="drawer-footer" | Aktionen. |
| Prop | Typ | Standard |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <h2> |
| Attribut | Beschreibung |
|---|---|
data-slot="drawer-title" | Beschriftet den Drawer. |
| Prop | Typ | Standard |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <p> |
| Attribut | Beschreibung |
|---|---|
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.
| Prop | Typ | Standard |
|---|---|---|
children | ReactNode | – |
| Attribut | Beschreibung |
|---|---|
--drawer-keyboard-inset | Wird auf den Viewport gesetzt, solange die Tastatur geöffnet ist: wie viel davon die Seite überlappt. Verwende es mit einem Fallback von 0px. |
| Prop | Typ | Standard |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribut | Beschreibung |
|---|---|
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.
- SheetEin Panel, das von jeder Kante hereingleitet, mit Wischen zum Schließen, Scroll-Sperre und gestapelter Verschachtelung.
- Alert dialogEin Bestätigungsdialog für destruktive oder wichtige Aktionen, der auf asynchrone Arbeit wartet und auf Smartphones zum Bottom Sheet wird.
- CommandEine durchsuchbare Liste von Aktionen, inline oder als ⌘K-Palette, mit Seiten, Tastenkürzeln und hervorgehobenen Treffern.
- Context menuEin Menü mit Aktionen per Rechtsklick oder langem Drücken, mit Untermenüs, Checkbox- und Radio-Einträgen sowie Halte-Feedback auf Touch-Geräten.
- DialogEin Fenster über der Seite für Formulare und fokussierte Aufgaben, mit fixiertem Header und Footer, Verschachtelung und einem wischbaren Bottom Sheet auf Smartphones.
- Dropdown menuEin Menü mit Aktionen und Optionen hinter einem Button, mit Gruppen, Untermenüs, Checkbox- und Radio-Einträgen sowie Tastenkürzeln.
In Blocks verwendet
Blocks, die auf Drawer aufbauen.