Components
Drawer

Drawer

A panel that slides in from the edge of the screen, typically used for navigation or forms.

Loading...

Anatomy

<Drawer.Root>
  <Drawer.Trigger />
  <Drawer.Backdrop />
  <Drawer.Positioner>
    <Drawer.Content>
      <Drawer.Grabber>
        <Drawer.GrabberIndicator />
      </Drawer.Grabber>
      <Drawer.Title />
      <Drawer.Description />
      <Drawer.CloseTrigger />
    </Drawer.Content>
  </Drawer.Positioner>
</Drawer.Root>

Examples

Swipe Direction

Use the swipeDirection prop to control which edge the drawer slides in from.

Snap Points

Use the snapPoints prop to define intermediate positions the drawer can snap to.

Set modal to false to allow interaction with the rest of the page while the drawer is open.

Controlled

Use the open and onOpenChange props to control the drawer state.

Scrollable

No Drag Area

Apply the data-no-drag attribute to any element inside the drawer to prevent dragging from starting on it.

Non Draggable

Set draggable to false to disable drag-to-dismiss entirely.

Indent Background

Use Drawer.IndentBackground to create a visual indent effect on the page behind the drawer.

Multiple Triggers

Use the value prop on Drawer.Trigger to share a single drawer across multiple trigger elements. The onTriggerValueChange callback fires when a different trigger is activated.

Using the Root Provider

Use the useDrawer hook and Drawer.RootProvider to control the drawer from outside the component tree.

Guides

Styling by Swipe Direction

The Drawer.Content elements expose a data-swipe-direction attribute (up | down | left | right) that reflects the resolved physical direction the drawer slides in from.

Target it to apply direction-aware styles — for example, rounded corners on the side facing the viewport:

[data-scope='drawer'][data-part='content'] {
  /* Top drawer */
  &[data-swipe-direction='up'] {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    border-bottom-left-radius: 16px;
    border-bottom-right-radius: 16px;
  }

  /* Bottom drawer */
  &[data-swipe-direction='down'] {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
  }

  /* Left drawer */
  &[data-swipe-direction='left'] {
    border-top-left-radius: 0;
    border-bottom-right-radius: 16px;
    border-top-left-radius: 16px;
    border-top-right-radius: 0;
  }

  /* Right drawer */
  &[data-swipe-direction='right'] {
    border-top-right-radius: 0;
    border-bottom-left-radius: 16px;
    border-top-left-radius: 0;
    border-top-right-radius: 16px;
  }
}

Preventing Overdrag Gaps

When a user drags the drawer past its open position, a small gap can appear between the drawer content and the viewport edge. To prevent this, extend the drawer's background beyond its visible bounds using a CSS ::after pseudo-element:

[data-scope='drawer'][data-part='content'] {
  --bleed: 3rem;
  position: relative;

  /* Bleed effect */
  &::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    top: 100%;
    height: var(--bleed);
    background-color: inherit;
    pointer-events: none;
  }
}

For side drawers, adjust the pseudo-element to extend horizontally:

[data-scope='drawer'][data-part='content'] {
  /* Right drawer */
  &[data-swipe-direction='right']::after {
    inset-inline: auto;
    inset-block: 0;
    top: 0;
    left: 100%;
    width: var(--bleed);
    height: auto;
  }

  /* Left drawer */
  &[data-swipe-direction='left']::after {
    inset-inline: auto;
    inset-block: 0;
    top: 0;
    right: 100%;
    width: var(--bleed);
    height: auto;
  }
}

The ::after element inherits the drawer's background color and sits just outside the content bounds. During overdrag, the dampened movement reveals this extension instead of an empty gap.

API Reference

Props

Root

PropDefaultType
closeOnEscapetrue
boolean

Whether to close the drawer when the escape key is pressed.

closeOnInteractOutsidetrue
boolean

Whether to close the drawer when the outside is clicked.

closeThreshold0.25
number

The threshold distance for dismissing the drawer.

defaultOpen
boolean

The initial open state of the drawer.

defaultSnapPoint
SnapPoint

finalFocusEl
() => MaybeElement

Element to receive focus when the sheet is closed.

id
string

The unique identifier of the machine.

ids
Partial<{ backdrop: string positioner: string content: string title: string header: string trigger: string grabber: string grabberIndicator: string closeTrigger: string }>

The ids of the elements in the drawer. Useful for composition.

immediate
boolean

Whether to synchronize the present change immediately or defer it to the next frame

initialFocusEl
() => MaybeElement

Element to receive focus when the sheet is opened.

lazyMountfalse
boolean

Whether to enable lazy mounting

modaltrue
boolean

Whether to prevent pointer interaction outside the element and hide all content below it.

onEscapeKeyDown
(event: KeyboardEvent) => void

Function called when the escape key is pressed

onExitComplete
VoidFunction

Function called when the animation ends in the closed state

onFocusOutside
(event: FocusOutsideEvent) => void

Function called when the focus is moved outside the component

onInteractOutside
(event: InteractOutsideEvent) => void

Function called when an interaction happens outside the component

onOpenChange
(details: OpenChangeDetails) => void

Function called when the open state changes.

onPointerDownOutside
(event: PointerDownOutsideEvent) => void

Function called when the pointer is pressed down outside the component

onRequestDismiss
(event: LayerDismissEvent) => void

Function called when this layer is closed due to a parent layer being closed

onSnapPointChange
(details: SnapPointChangeDetails) => void

Callback fired when the snap point changes.

open
boolean

Whether the drawer is open.

present
boolean

Whether the node is present (controlled by the user)

preventDragOnScrolltrue
boolean

Whether to prevent dragging on scrollable elements. When enabled, the sheet will not start dragging if the user is interacting with a scrollable element.

preventScrolltrue
boolean

Whether to prevent scrolling behind the sheet when it's opened

restoreFocustrue
boolean

Whether to restore focus to the element that had focus before the sheet was opened.

role'dialog'
'dialog' | 'alertdialog'

The sheet's role

skipAnimationOnMountfalse
boolean

Whether to allow the initial presence animation.

snapPoint
SnapPoint

The currently active snap point.

snapPoints[1]
SnapPoint[]

The snap points of the drawer. Array of numbers or strings representing the snap points.

snapToSequentialPointsfalse
boolean

Whether the drawer should snap to sequential points when swiping.

stack
DrawerStack

Optional external store for coordinating app-level drawer stack visuals (e.g. indent and background layers).

swipeDirection'down'
SwipeDirection

The direction in which the drawer can be swiped.

swipeVelocityThreshold700
number

The threshold velocity (in pixels/s) for closing the drawer.

trapFocustrue
boolean

Whether to trap focus inside the sheet when it's opened.

unmountOnExitfalse
boolean

Whether to unmount on exit.

Backdrop

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
AttributeDescription
[data-scope]drawer
[data-part]backdrop
[data-state]"open" | "closed"
[data-swiping]
CSS VariableDescription
--drawer-swipe-progressThe drawer swipe progress value for the Backdrop
--drawer-swipe-strengthThe drawer swipe strength value for the Backdrop
--layer-indexThe index of the dismissable in the layer stack

CloseTrigger

Renders a <button> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Content

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
draggabletrue
boolean

Whether the drawer content is draggable. If false, the drawer can only be dragged by the grabber.

AttributeDescription
[data-scope]drawer
[data-part]content
[data-state]"open" | "closed"
[data-expanded]Present when expanded
[data-swipe-direction]
[data-swiping]
[data-dragging]Present when in the dragging state
CSS VariableDescription
--drawer-translateThe drawer translate value for the Content
--drawer-translate-xThe drawer translate x value for the Content
--drawer-translate-yThe drawer translate y value for the Content
--drawer-snap-point-offset-xThe offset position for drawer snap point
--drawer-snap-point-offset-yThe offset position for drawer snap point
--drawer-swipe-movement-xThe drawer swipe movement x value for the Content
--drawer-swipe-movement-yThe drawer swipe movement y value for the Content
--drawer-swipe-strengthThe drawer swipe strength value for the Content
--layer-indexThe index of the dismissable in the layer stack
--nested-layer-countThe number of nested drawers

GrabberIndicator

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Grabber

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

IndentBackground

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Indent

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Positioner

Renders a <div> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
AttributeDescription
[data-scope]drawer
[data-part]positioner
[data-state]"open" | "closed"
[data-swipe-direction]

RootProvider

PropDefaultType
value
UseDrawerReturn

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
immediate
boolean

Whether to synchronize the present change immediately or defer it to the next frame

lazyMountfalse
boolean

Whether to enable lazy mounting

onExitComplete
VoidFunction

Function called when the animation ends in the closed state

present
boolean

Whether the node is present (controlled by the user)

skipAnimationOnMountfalse
boolean

Whether to allow the initial presence animation.

unmountOnExitfalse
boolean

Whether to unmount on exit.

Title

Renders a <h2> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Trigger

Renders a <button> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
AttributeDescription
[data-scope]drawer
[data-part]trigger
[data-value]The value of the item
[data-state]"open" | "closed"
[data-current]Present when current

Context

API

PropertyType
open
boolean

Whether the drawer is open.

dragging
boolean

Whether the drawer is currently being dragged.

triggerValue
string | null

The value of the active trigger.

setTriggerValue
(value: string | null) => void

Set the active trigger value.

setOpen
(open: boolean) => void

Function to open or close the menu.

snapPoints
SnapPoint[]

The snap points of the drawer.

swipeDirection
SwipeDirection

The swipe direction of the drawer.

snapPoint
SnapPoint | null

The currently active snap point.

setSnapPoint
(snapPoint: SnapPoint | null) => void

Function to set the active snap point.

getOpenPercentage
() => number

Get the current open percentage of the drawer.

getSnapPointIndex
() => number

Get the index of the currently active snap point.

getContentSize
() => number | null

Get the current main-axis size of the drawer content.

Accessibility

Complies with the Dialog WAI-ARIA design pattern.

KeyDescription
Enter
When focus is on the trigger, opens the dialog.
Tab
Moves focus to the next focusable element within the content. Focus is trapped within the dialog.
Shift + Tab
Moves focus to the previous focusable element. Focus is trapped within the dialog.
Esc
Closes the dialog and moves focus to trigger or the defined final focus element