Skip to main content

drawer

A customizable drawer component for React.

Features

  • Background Scaling: Scales the background when the drawer is open using [vaul-drawer-wrapper].
  • Custom Close Threshold: Controls when the drawer should close based on swipe distance (0 to 1).
  • Scroll Lock Timeout: Sets a delay for drawer drag after scrolling (default: 500ms).
  • Snap Points: Defines percentage or pixel values for drawer screen coverage.
  • Fade Effect: Applies a fade effect from a specific snap point.
  • Modal Control: Allows interaction with elements outside the drawer (default: true).
  • Handle-Only Dragging: Restricts drawer dragging to <Drawer.Handle /> (default: false).
  • Directional Control: Opens drawer from top, bottom, left, or right (default: bottom).
  • Scroll Restoration Prevention: Avoids restoring scroll after navigation within the drawer (default: true).
  • Disable Scroll Prevention: Disables scroll prevention to fix autofocus issues (default: true).
  • No Body Styles: Prevents Vaul from applying styles to the body (default: false).
  • Background Color on Scale: Controls background color change when the drawer opens (default: true).
  • No Drag Attribute: Prevents drawer dragging when interacting with elements marked [data-vaul-no-drag].

About

Drawer is built on Vaul by emilkowalski_.

Philosophy

Drawers are the mobile-native sibling of sheets — they respond to drag gestures and snap to natural positions. We wrap Vaul because gesture physics and spring animations are notoriously hard to get right. The result feels native on touch devices while degrading gracefully to a standard overlay on desktop.

How It's Built

Loading diagram...

Installation


npx @gentleduck/cli add drawer

npx @gentleduck/cli add drawer

Usage

import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from '@/components/ui'
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from '@/components/ui'
<Drawer>
  <DrawerTrigger>Open</DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Are you absolutely sure?</DrawerTitle>
      <DrawerDescription>This action cannot be undone.</DrawerDescription>
    </DrawerHeader>
    <DrawerFooter>
      <Button>Submit</Button>
      <DrawerClose>
        <Button variant="outline">Cancel</Button>
      </DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>
<Drawer>
  <DrawerTrigger>Open</DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Are you absolutely sure?</DrawerTitle>
      <DrawerDescription>This action cannot be undone.</DrawerDescription>
    </DrawerHeader>
    <DrawerFooter>
      <Button>Submit</Button>
      <DrawerClose>
        <Button variant="outline">Cancel</Button>
      </DrawerClose>
    </DrawerFooter>
  </DrawerContent>
</Drawer>

Examples

Drawer

using the normal one.

Responsive Dialog

Use Dialog and Drawer together to create a responsive dialog. It renders Dialog on desktop and Drawer on mobile.

Non-dismissible

A non-dismissible drawer For cases when your drawer has to be always visible, Nothing will close it unless you make it controlled and close it programmatically.

Non-modal

Custom Drawer

Component Composition

Loading diagram...

API Reference

Drawer

PropTypeDefaultDescription
shouldScaleBackgroundbooleantrueWhether to scale the background when drawer is open
dir'ltr' | 'rtl'--Text direction used to resolve horizontal drawer side in RTL/LTR. Resolved by primitives useDirection (dir prop -> DirectionProvider -> 'ltr').
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Root>--Additional props inherited from Drawer.Root.

DrawerTrigger

Wrapper around DrawerPrimitive.Trigger. Used to toggle the drawer open or closed.

PropTypeDefaultDescription
classNamestring--Additional CSS classes applied to the trigger
childrenReact.ReactNode--Trigger content
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Trigger>--Additional props inherited from Drawer.Trigger.

DrawerPortal

Wrapper around DrawerPrimitive.Portal. Renders drawer content in a React Portal.

PropTypeDefaultDescription
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Portal>--Additional props inherited from Drawer.Portal.

DrawerClose

Wrapper around DrawerPrimitive.Close. Closes the drawer when clicked.

PropTypeDefaultDescription
classNamestring--Additional CSS classes applied to the close element
childrenReact.ReactNode--Close button content
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Close>--Additional props inherited from Drawer.Close.

DrawerOverlay

PropTypeDefaultDescription
classNamestring--Additional CSS classes applied to the overlay
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>--Additional props inherited from Drawer.Overlay.

DrawerContent

PropTypeDefaultDescription
classNamestring--Additional CSS classes applied to the content panel
childrenReact.ReactNode--Drawer inner content
dir'ltr' | 'rtl'--Text direction override. Resolved via useDirection (dir prop -> DirectionProvider -> 'ltr').
overlayPropsReact.ComponentPropsWithoutRef<typeof DrawerOverlay>--Props forwarded to the DrawerOverlay
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>--Additional props inherited from Drawer.Content.

DrawerHeader

PropTypeDefaultDescription
classNamestring--Additional CSS classes applied to the header
childrenReact.ReactNode--Header content
...propsReact.HTMLProps<HTMLDivElement>--Additional props to spread to the content div

DrawerFooter

PropTypeDefaultDescription
dir'ltr' | 'rtl'--Text direction override. Resolved via useDirection (dir prop -> DirectionProvider -> 'ltr').
classNamestring--Additional CSS classes applied to the footer
childrenReact.ReactNode--Footer content
...propsReact.HTMLProps<HTMLDivElement>--Additional props to spread to the content div

DrawerTitle

PropTypeDefaultDescription
dir'ltr' | 'rtl'--Text direction override. Resolved via useDirection (dir prop -> DirectionProvider -> 'ltr').
classNamestring--Additional CSS classes applied to the title
childrenReact.ReactNode--Title text
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>--Additional props inherited from Drawer.Title.

DrawerDescription

PropTypeDefaultDescription
dir'ltr' | 'rtl'--Text direction override. Resolved via useDirection (dir prop -> DirectionProvider -> 'ltr').
classNamestring--Additional CSS classes applied to the description
childrenReact.ReactNode--Description text
...propsReact.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>--Additional props inherited from Drawer.Description.

RTL Support

Set dir="rtl" on Drawer for a local override, or set DirectionProvider once at app/root level for global direction. Horizontal drawers (left/right) are resolved automatically for RTL/LTR.

See also

  • Dialog — Centered modal overlay
  • Sheet — Side panel overlay