Composables
ComposableBuilt onDialog

Drawer

Swipeable slide-in panel with snap points for mobile-friendly interactions

The drawer is a swipeable panel that slides in from a screen edge and rests at configurable snap points. Use it for mobile-style bottom sheets, multi-height panels like a music player, or any surface a user drags between heights. For a plain slide-in panel without snap points or drag gestures, use Sheet instead.

Preview

Installation

Usage

Composition

DrawerContent composes the portal, backdrop, viewport, and popup. Use DrawerBody for scrollable content that cooperates with swipe gestures.

Examples

Controlled

Use open and onOpenChange to drive the drawer's open state externally.

Drawer is closed

Directions

Use direction to choose which edge the drawer slides in from.

ValueDescription
"bottom"Slides up from the bottom (default).
"top"Slides down from the top.
"left"Slides in from the left.
"right"Slides in from the right.

Snap Points

Use snapPoints to let the drawer rest at multiple heights.

Pixel-Based Snap Points

Pass pixel strings in snapPoints for fixed heights that ignore content size.

Sequential Snap Points

Set sequentialSnap to stop at each snap point instead of skipping them on fast swipes.

Floating Variant

Use variant="floating" for an inset, modal-like panel with rounded corners and shadow.

Music Player

Combine snap points with --drawer-snap-progress for progressive disclosure: mini player, expanded controls, and full queue.

Scrollable Content

Use DrawerBody for scrollable content that cooperates with swipe gestures.

With Form

Place form fields inside DrawerBody, with actions in DrawerFooter.

Set footerVariant="inset" on DrawerContent for a separated footer with a muted background and top border.

Add className="sticky bottom-0" to DrawerFooter to pin it as the drawer is dragged down.

Nested

Open a drawer from inside another; the parent scales down and dims behind the nested drawer.

Non-Modal

Use modal to control focus trapping and page interaction.

ValueDescription
trueFocus trapped, backdrop shown, body scroll locked (default).
"trap-focus"Focus trapped, but the page stays interactive.
falseNo focus trap, no backdrop; the page is fully interactive.

Accessibility

Include a DrawerTitle (and ideally a DrawerDescription) inside every DrawerContent so the dialog is named for assistive technology. When the modal drawer opens, focus moves into it and is trapped until it closes; modal="trap-focus" keeps the trap while leaving the page interactive, and modal={false} removes the trap entirely. DrawerHandle is a real button labeled "Close drawer" by default; set preventClose to relabel it "Drawer handle" when it should not dismiss.

API Reference

The Drawer component is built on top of Base UI's Dialog. All Base UI props are supported. The documentation below only covers custom props specific to our implementation.

For the complete Base UI API, see the Base UI Dialog documentation.

Props

Drawer

Root component that manages drawer state and provides context to child components. Wraps Base UI's Dialog.Root.

Prop

DrawerContent

Main drawer container with swipe gesture handling and positioning. Composes Dialog.Portal, Dialog.Backdrop, Dialog.Viewport, and Dialog.Popup. Props are forwarded to Dialog.Popup.

Prop

DrawerBody

Scrollable content area with adaptive padding based on surrounding elements. Wraps ScrollArea.

Prop

DrawerHandle

Visual drag indicator that doubles as a close button. Automatically adjusts orientation based on drawer direction.

Prop

Components

ComponentDescription
DrawerRoot component that manages state and provides context
DrawerTriggerButton that opens the drawer
DrawerPortalRenders drawer content into a portal
DrawerContentMain content container with swipe gesture handling
DrawerHandleVisual drag indicator (automatically adjusts for direction)
DrawerHeaderContainer for title and description with adaptive padding
DrawerTitleAccessible title element
DrawerDescriptionAccessible description element
DrawerBodyScrollable content area with adaptive padding
DrawerFooterContainer for action buttons, supports inset variant via content
DrawerCloseButton that closes the drawer
useDrawerHook to access drawer context (direction, snap state, etc.)

Nested Scrollable Content

Use DrawerBody for scrollable content inside the drawer. The component handles overflow automatically and adapts its padding based on surrounding elements (header, footer).

Animating Content Based on Snap Position

The drawer exposes a --drawer-snap-progress CSS custom property that animates from 0 (first snap) to 1 (last snap) as the drawer moves between snap points. This works in all browsers:

  • Chrome 115+: GPU-accelerated CSS scroll-driven animation (no React re-renders)
  • Other browsers: JavaScript fallback sets the variable automatically

Using the CSS Variable

Use --drawer-snap-progress directly in your styles for crossfade effects:

Or with Tailwind's arbitrary value syntax:

Conditional Logic with Render Props

CSS variables work great for visual properties like opacity, but some properties like pointer-events need conditional logic. Use the render prop pattern for these:

Render Prop Values

ValueDescription
snapProgressProgress between snap points (0 = first snap, 1 = last snap)
dragProgressProgress toward closed (0 = open, 1 = closed)
isDraggingWhether currently being dragged/scrolled
activeSnapPointCurrent active snap point value