HextaUI

Drawer

Un panneau qui glisse depuis n’importe quel bord et suit votre doigt, avec des points d’accroche, une poignée fonctionnelle et des drawers imbriqués qui s’empilent.

"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

Ajoute le composant, les tokens de thème HextaUI et les composants HextaUI dont il dépend.

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

Directions

Définissez swipeDirection sur <Drawer /> pour choisir le bord. Le drawer s’ouvre depuis ce bord et se balaie en retour vers lui. Les drawers du haut et du bas affichent une poignée par défaut.

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

Points d’accroche

Passez snapPoints pour stabiliser un drawer du bas à des hauteurs prédéfinies. Les nombres de 0 à 1 sont des fractions du viewport, les nombres plus grands des pixels, et les chaînes acceptent px ou rem. La partie visible s’adapte toujours à son contenu : rien ne se cache sous l’écran.

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

Contenu défilant

<DrawerBody /> défile de lui-même : l’en-tête et le pied de page restent en place. Le balayage ne démarre qu’une fois le corps revenu tout en haut.

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

Formulaires et clavier

Enveloppez <DrawerContent /> dans <DrawerVirtualKeyboardProvider /> lorsqu’un drawer du bas contient des champs de texte. Sur téléphone, le champ ayant le focus défile dans la vue au-dessus du clavier logiciel au lieu de se cacher derrière. Gardez les champs dans <DrawerBody /> pour que l’en-tête et le pied de page restent en place.

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

Imbriqué

Un drawer ouvert depuis un drawer du même bord s’empile par-dessus. Ceux de derrière rétrécissent, dépassent au-dessus et suivent votre doigt lorsque vous balayez celui du dessus pour l’écarter.

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

Confirmer depuis un drawer

Les boîtes de dialogue, boîtes de dialogue d’alerte, sheets et drawers d’un autre bord se superposent au lieu de s’empiler. Le drawer recule et un arrière-plan plus clair le recouvre.

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

Changez swipeDirection avec une media query pour afficher un panneau latéral sur ordinateur et une bottom sheet sur téléphone.

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

Non modal

Avec modal={false}, il n’y a pas d’arrière-plan, la page continue de défiler et le focus peut quitter le 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>
  )
}

Contrôlé

Passez open et onOpenChange pour l’ouvrir de n’importe où, sans déclencheur.

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

Déclencheurs détachés

Partagez un drawer entre plusieurs déclencheurs avec createDrawerHandle. Chaque déclencheur transmet un payload que le drawer rend via un enfant fonction.

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

De droite à gauche

Passez dir="rtl" à <DrawerContent /> pour inverser son contenu. swipeDirection désigne un bord physique : "left" reste donc à gauche et la poignée reste sur le bord intérieur.

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>
  )
}
ToucheAction
EnterSpaceSur le déclencheur, ouvre le drawer et déplace le focus à l’intérieur.
TabShift + TabPasse d’un élément focusable à l’autre. Le focus reste dans un drawer modal.
EscFerme le drawer le plus haut et rend le focus à son déclencheur.
  • Le drawer est une boîte de dialogue. <DrawerTitle /> l’étiquette et <DrawerDescription /> le décrit : incluez donc toujours un titre.
  • Le balayage n’est jamais la seule sortie : Escape, l’arrière-plan et un bouton <DrawerClose /> le ferment aussi.
  • La poignée est décorative et masquée aux technologies d’assistance. À la souris, le texte dans le drawer peut être sélectionné sans le faire glisser.
  • Avec la réduction des animations, le drawer apparaît et disparaît en fondu au lieu de glisser. Le glissement suit toujours le pointeur.

Construit sur le drawer de Base UI. Chaque partie accepte les props de la primitive qu’elle enveloppe.

PropTypePar défaut
swipeDirectionLe bord depuis lequel il s’ouvre et la direction qui le ferme.
"up" | "down" | "left" | "right""down"
showSwipeHandleAffiche la poignée. Par défaut true pour haut et bas, false pour gauche et droite.
boolean–
snapPointsHauteurs auxquelles un drawer vertical peut se stabiliser. 0 à 1 correspond à une fraction du viewport, >1 à des pixels, et les chaînes acceptent px ou rem.
(number | string)[]–
snapPoint
number | string | null–
defaultSnapPoint
number | string | null–
onSnapPointChange
(snapPoint, details) => void–
defaultOpen
booleanfalse
open
boolean–
onOpenChange
(open: boolean, details) => void–
onOpenChangeCompleteAppelé à la fin de l’animation d’ouverture ou de fermeture.
(open: boolean) => void–
modalL’arrière-plan n’est rendu que si true.
boolean | "trap-focus"true
disablePointerDismissalLe garde ouvert lors d’un clic sur l’arrière-plan.
booleanfalse
handle
DrawerHandle<Payload>–
children
ReactNode | ({ payload }) => ReactNode–
PropTypePar défaut
handle
DrawerHandle<Payload>–
payload
Payload–
render
ReactElement | (props, state) => ReactElement<button>
AttributDescription
data-slot="drawer-trigger"Ciblez le déclencheur en CSS.
data-popup-openPrésent tant que son drawer est ouvert.

Rend le portail, l’arrière-plan, le viewport et la popup, ainsi que la poignée. Les drawers verticaux s’adaptent à leur contenu jusqu’à la hauteur du viewport moins 4 rem. Les drawers latéraux font 75 % de large, jusqu’à 24 rem à partir du breakpoint sm. Remplacez avec h-* ou w-*, ou limitez-vous à un axe avec data-[swipe-axis=y]:.

PropTypePar défaut
initialFocus
boolean | RefObject | (type) => HTMLElement | boolean–
finalFocus
boolean | RefObject | (type) => HTMLElement | boolean–
className
string | (state) => string–
render
ReactElement | (props, state) => ReactElement<div>
AttributDescription
data-slot="drawer-popup"Le panneau du drawer.
data-slot="drawer-content"L’enveloppe interne autour de vos enfants. Elle défile quand rien d’autre ne le fait.
data-swipe-directionup, right, down ou left.
data-swipe-axisx ou y.
data-openPrésent tant que le drawer est ouvert.
data-starting-stylePrésent pendant l’animation d’entrée.
data-ending-stylePrésent pendant l’animation de sortie.
data-swipingPrésent pendant qu’on le fait glisser.
data-snap-pointsPrésent lorsque le drawer a des points d’accroche.
data-expandedPrésent au point d’accroche pleine hauteur.
data-nested-drawer-openPrésent tant qu’un autre drawer est ouvert par-dessus.
data-stackPrésent tant qu’un drawer du même bord est empilé par-dessus.
--drawer-insetDétache le drawer des bords du viewport. 0px par défaut.
--drawer-bleed-backgroundRemplit la zone révélée lorsqu’on tire au-delà du bord. Par défaut, la couleur du popover.
--drawer-swipe-movement-xDistance de glissement horizontale. Une variable -y existe aussi.
--drawer-snap-point-offsetÀ quelle distance sous le haut se trouve le point d’accroche actuel.
--nested-drawersNombre de drawers ouverts par-dessus.

Rendu par <DrawerContent /> lorsque modal vaut true. Il s’estompe pendant le balayage et reste visible au moins à moitié lorsqu’il y a des points d’accroche. Un drawer superposé à une sheet ou à un drawer d’un autre bord reçoit un arrière-plan plus clair.

AttributDescription
data-slot="drawer-overlay"L’arrière-plan.
data-nestedPrésent sur les arrière-plans plus clairs des drawers superposés.
--drawer-overlay-min-opacityL’opacité minimale atteinte pendant le balayage. 0, ou 0,5 avec des points d’accroche.

Rendu par <DrawerContent /> sur le bord intérieur lorsque showSwipeHandle est activé. Tout le drawer peut être glissé : la poignée n’est donc qu’un repère visuel.

AttributDescription
data-slot="drawer-swipe-handle"La poignée.

De simples éléments <div> qui mettent en page le drawer. L’en-tête centre son texte dans les drawers verticaux sur petit écran, le corps défile et prend l’espace restant, et le pied de page empile ses actions.

AttributDescription
data-slot="drawer-header"Titre et description.
data-slot="drawer-body"Contenu défilant.
data-slot="drawer-footer"Actions.
PropTypePar défaut
render
ReactElement | (props, state) => ReactElement<h2>
AttributDescription
data-slot="drawer-title"Étiquette le drawer.
PropTypePar défaut
render
ReactElement | (props, state) => ReactElement<p>
AttributDescription
data-slot="drawer-description"Décrit le drawer.

Ne rend aucun élément. Placez-le dans <Drawer />, autour de <DrawerContent />. Tant que le clavier logiciel est ouvert, il ajoute de l’espace sous le conteneur de défilement du drawer, fait défiler le champ ayant le focus dans la vue et fait en sorte qu’un appui sur un champ ouvre le clavier sur iOS. Les drawers sans lui ne sont pas affectés.

PropTypePar défaut
children
ReactNode–
AttributDescription
--drawer-keyboard-insetDéfini sur le viewport pendant que le clavier est ouvert : la part du viewport qu’il recouvre. À utiliser avec une valeur de repli de 0px.
PropTypePar défaut
render
ReactElement | (props, state) => ReactElement<button>
AttributDescription
data-slot="drawer-close"Ferme le drawer lorsqu’il est pressé.

createDrawerHandle<Payload>() renvoie un handle qui relie un <Drawer /> à des déclencheurs rendus ailleurs. Créez-le une seule fois, en dehors de votre composant.

Utilisé dans les blocks

Des blocks qui s’appuient sur Drawer.