Toggle Sidebar B
AppearanceLight & dark mode D

Drawer

A panel that slides in from the edge of the screen with swipe gestures, snap points, and nested drawer support.

Overview

Slides up from the bottom edge with a drag bar and a bare footer.

Replay preview

Inset variant

Set variant to inset so the panel floats away from the screen edges on larger viewports.

Replay preview

Straight variant

Set variant to straight to drop the rounded corners and the stacking scale.

Replay preview

Scrollable content

Wrap long content in DrawerPanel. The list scrolls normally while the panel stays draggable from anywhere on its body.

Replay preview

Nested drawers

Nest a Drawer inside another and the one behind shrinks back, recovering as you swipe the front one away.

Replay preview

Snap points

Pass snapPoints to stop the drawer at preset heights. Values below 1 are viewport fractions, anything else is a length. Snap points apply to top and bottom drawers only.

Replay preview

Mobile menu

A left drawer holding navigation links that close the panel on tap.

Replay preview

Responsive dialog

Use Drawer on small screens and Dialog on larger ones to show the same content in a modal on desktop and a bottom sheet on mobile.

Replay preview

Responsive menu

Pair Drawer with DropdownMenu so actions appear in a dropdown on desktop and a swipe-up sheet on mobile. Use DrawerMenuTrigger for items that open nested drawers on mobile, and DrawerMenuGroupLabel as the section title — swipe to go back.

Replay preview

Anatomy

Import all parts and piece them together.

vue
<script setup>
import {
  Drawer,
  DrawerBar,
  DrawerClose,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerMenu,
  DrawerMenuCheckboxItem,
  DrawerMenuGroup,
  DrawerMenuGroupLabel,
  DrawerMenuItem,
  DrawerMenuRadioGroup,
  DrawerMenuRadioItem,
  DrawerMenuSeparator,
  DrawerMenuTrigger,
  DrawerPanel,
  DrawerPopup,
  DrawerSwipeArea,
  DrawerTitle,
  DrawerTrigger,
} from "@/components/ui/drawer";
</script>

<template>
  <Drawer>
    <DrawerTrigger />
    <DrawerSwipeArea />
    <DrawerPopup>
      <DrawerHeader>
        <DrawerTitle />
        <DrawerDescription />
      </DrawerHeader>
      <DrawerPanel>
        <DrawerMenu>
          <DrawerMenuGroup>
            <DrawerMenuGroupLabel />
            <DrawerMenuItem />
          </DrawerMenuGroup>
          <DrawerMenuSeparator />
          <DrawerMenuCheckboxItem />
          <DrawerMenuRadioGroup>
            <DrawerMenuRadioItem />
          </DrawerMenuRadioGroup>
          <DrawerMenuTrigger />
        </DrawerMenu>
      </DrawerPanel>
      <DrawerFooter>
        <DrawerClose />
      </DrawerFooter>
      <DrawerBar />
    </DrawerPopup>
  </Drawer>
</template>

API Reference

Drawer

PropTypeDefaultDescription
openbooleanOpen state. Supports v-model:open.
defaultOpenbooleanfalseOpen state when the drawer is left uncontrolled.
side"top" | "right" | "bottom" | "left""bottom"Edge the drawer slides in from. Sets the swipe direction and flows to every part through context.
modalboolean | "trap-focus"trueTrap focus and lock scrolling. Use trap-focus to keep the page interactive.
snapPoints(number | string)[]Preset stops. Numbers below 1 are viewport fractions; strings are px or rem lengths.
snapPointnumber | string | nullActive stop. Supports v-model:snapPoint. Null closes the drawer.
snapToSequentialPointsbooleanfalseMove one stop at a time instead of jumping to the nearest.
EventDescription
update:openFires when the drawer opens or closes. The browser back gesture also closes it.
update:snapPointFires when the active snap point changes.

DrawerTrigger

PropTypeDefaultDescription
asChildbooleanfalseMerge props onto the child element instead of rendering a button.
togglebooleanfalseClose the drawer when pressed while it is open, instead of only opening it. For a trigger that doubles as the close control, such as a menu button that morphs into a cross. Such a trigger also needs pointer-events-auto, since the scroll lock makes the body inert.

DrawerPopup

PropTypeDefaultDescription
variant"default" | "straight" | "inset""default"Corner and edge treatment. Straight drops the rounded corners and the stacking scale; inset floats the panel away from the screen edges from the sm breakpoint up.
showBarbooleanfalseRender the drag bar.
showCloseButtonbooleanfalseRender a close button in the top corner.
showOverlaybooleantrueRender the backdrop. Turning it off also gives up the scroll lock it carries.
overlayClassstringClasses for the backdrop, e.g. to keep it mounted but invisible.
viewportClassstringClasses for the viewport, the fixed box the panel is laid out in. Reach for it when the drawer must not start at the edge of the screen, e.g. a menu that hangs below a sticky header.
swipeArbitrationbooleantrueDecide per gesture whether a drag belongs to the panel or to a scroller inside it.
virtualKeyboardbooleantrueLift the panel clear of the software keyboard and scroll the focused field into view. Turn it off for a drawer that never holds a field.

DrawerHeader

PropTypeDefaultDescription
allowSelectionbooleanfalseLet the mouse select the header text instead of treating it as a drag surface. Touch always drags.

DrawerPanel

PropTypeDefaultDescription
scrollablebooleantrueWrap the content in a ScrollArea.
scrollFadebooleantrueFade content at the scroll edges. Only applies when scrollable.
allowSelectionbooleantrueLet the mouse select the content instead of treating it as a drag surface. Touch always drags.

DrawerFooter

PropTypeDefaultDescription
variant"default" | "bare""default"Bare drops the top border and the muted background.
allowSelectionbooleantrueLet the mouse select the footer text instead of treating it as a drag surface.

DrawerTitle / DrawerDescription

PropTypeDefaultDescription
asChildbooleanfalseMerge props onto the child element.

DrawerClose

PropTypeDefaultDescription
asChildbooleanfalseMerge props onto the child element.

DrawerBar

PropTypeDefaultDescription
position"top" | "right" | "bottom" | "left"from contextOverride the edge the bar aligns to. Rendered automatically when showBar is set on DrawerPopup.

DrawerSwipeArea

PropTypeDefaultDescription
position"top" | "right" | "bottom" | "left"from contextEdge strip that opens the drawer when swiped from outside. Must sit inside Drawer.

DrawerMenu

PropTypeDefaultDescription
classstringContainer for menu items, rendered as a nav.

DrawerMenuItem

PropTypeDefaultDescription
variant"default" | "destructive""default"Destructive uses the destructive text colour.
disabledbooleanfalseDisable the item.

DrawerMenuTrigger

PropTypeDefaultDescription
classstringMenu item that opens a nested drawer, with a trailing chevron. Wraps DrawerTrigger.

DrawerMenuCheckboxItem

PropTypeDefaultDescription
modelValuebooleanChecked state. Supports v-model.
defaultValuebooleanfalseChecked state when left uncontrolled.
variant"default" | "switch""default"Switch renders a toggle on the trailing edge instead of a leading check.
disabledbooleanfalseDisable the item.
EventDescription
update:modelValueFires when the item is toggled.

DrawerMenuRadioGroup

PropTypeDefaultDescription
modelValuestringSelected value. Supports v-model.
defaultValuestringSelected value when left uncontrolled.
EventDescription
update:modelValueFires when the selection changes.

DrawerMenuRadioItem

PropTypeDefaultDescription
valuestringValue this item selects. Required.
disabledbooleanfalseDisable the item.

DrawerMenuGroup / DrawerMenuGroupLabel / DrawerMenuSeparator

PropTypeDefaultDescription
classstringGrouping, section label and divider. In a nested menu the group label doubles as the screen title — swipe to go back.

DrawerPortal / DrawerBackdrop / DrawerViewport

PropTypeDefaultDescription
Re-exported reka-ui primitives. DrawerPopup renders all three internally, so reach for them only when composing the drawer by hand.

Accessibility

Keyboard shortcuts and ARIA behavior.

Shortcut Description
EscCloses the drawer.
TabFocus stays inside the drawer while it is open.
  • Every popup needs a DrawerTitle. Use the sr-only class when the design has no visible heading, as the menu examples do.
  • On touch devices the drawer is dragged toward its edge to dismiss, and a scroller inside it keeps scrolling normally.
  • A touch drag starts from anywhere on the panel, including buttons, links and form fields. With a mouse, regions marked allowSelection let you select text instead.
  • Add data-drawer-swipe-ignore to any subtree that runs its own touch gesture, such as a carousel or a slider.
  • Focusing a field raises the software keyboard and the drawer rises above it, then scrolls that field into view. The lift is published as --drawer-keyboard-inset on DrawerViewport, so a pinned footer of your own can offset itself by var(--drawer-keyboard-inset, 0px). Always keep the 0px fallback.