Morphos
Overlays

Drawer

A panel that slides in from an edge of the viewport, used for navigation or supplementary content.

Interactive example

Installation

npm install @morphos/overlays
pnpm add @morphos/overlays
yarn add @morphos/overlays
bun add @morphos/overlays

Import

import {
  Drawer,
  DrawerTrigger,
  DrawerContent,
  DrawerTitle,
  DrawerDescription,
  DrawerClose,
} from '@morphos/overlays'

Usage

@Component()
class MyComponent extends StatefulComponent {
  @State() drawer = new Drawer({ side: 'right' })

  render() {
    return (
      <>
        <DrawerTrigger drawer={this.drawer}>
          Open drawer
        </DrawerTrigger>
        <DrawerContent drawer={this.drawer} aria-labelledby="drawer-title">
          <DrawerTitle id="drawer-title">Settings</DrawerTitle>
          <DrawerDescription>Adjust your preferences below.</DrawerDescription>
          <p>Drawer body content.</p>
          <DrawerClose drawer={this.drawer}>Close</DrawerClose>
        </DrawerContent>
      </>
    )
  }
}

Compound components

ComponentDescription
DrawerRoot state manager. Owns open state and the side the panel slides from. Exposes openDrawer() / closeDrawer() / toggle().
DrawerTrigger<button> that opens the drawer. Sets aria-haspopup="dialog", aria-expanded, and data-open.
DrawerContentRenders into a Portal with a sibling backdrop <div data-morphos-backdrop>. Sets role="dialog", aria-modal="true", and data-side. Applies focus trap and scroll lock while open.
DrawerTitleRenders as <h2> by default (configurable via as).
DrawerDescriptionRenders as <p>.
DrawerClose<button> that calls closeDrawer().

The DrawerSide type

type DrawerSide = "top" | "right" | "bottom" | "left"

Controls which edge of the viewport DrawerContent slides in from, via the side prop on Drawer. The current value is reflected on DrawerContent as data-side so it can drive directional CSS animations.

Props — Drawer

PropTypeDefaultDescription
openbooleanControlled open state. When set, the consumer owns the state.
defaultOpenbooleanfalseInitial open state in uncontrolled mode.
onOpenChange(open: boolean) => voidCalled when the open state changes.
closeOnEscapebooleantrueWhether pressing Escape closes the drawer.
closeOnBackdropClickbooleantrueWhether clicking the backdrop closes the drawer.
sideDrawerSide"right"Which edge of the viewport the drawer slides from.
childrenChildrenContent — typically DrawerTrigger and DrawerContent.

Methods

MethodDescription
openDrawer()Opens the drawer. Emits onOpenChange(true).
closeDrawer()Closes the drawer. Emits onOpenChange(false).
toggle()Toggles the open state. Emits onOpenChange.

Props — DrawerTrigger

PropTypeDefaultDescription
drawerDrawerThe Drawer instance this trigger controls.
childrenChildrenThe trigger element content.
classstringCSS class.
idstringHTML id.

Props — DrawerContent

PropTypeDefaultDescription
drawerDrawerThe Drawer instance this content belongs to.
childrenChildrenDrawer body content.
classstringCSS class.
idstringHTML id. Falls back to an auto-generated id.
aria-labelstringAccessible label for the drawer.
aria-labelledbystringID of the element that labels the drawer (e.g. a DrawerTitle).
aria-describedbystringID of the element that describes the drawer (e.g. a DrawerDescription).

Props — DrawerTitle

PropTypeDefaultDescription
as"h1" | "h2" | "h3" | "h4" | "h5" | "h6""h2"The HTML heading element to render.
childrenChildrenTitle text.
classstringCSS class.
idstringHTML id.

Props — DrawerDescription

PropTypeDefaultDescription
childrenChildrenDescription text.
classstringCSS class.
idstringHTML id.

Props — DrawerClose

PropTypeDefaultDescription
drawerDrawerThe Drawer instance this close button controls.
childrenChildrenButton content.
classstringCSS class.
idstringHTML id.

data-* attributes

AttributeElementWhen present
data-openDrawerTriggerDrawer is open
data-openDrawerContent rootDrawer is open
data-sideDrawerContent rootAlways — reflects the side prop value ("top", "right", "bottom", or "left")

Use the data-side attribute on DrawerContent to apply directional slide-in animations via CSS. For example, [data-side="right"] slides in from the right.

DrawerContent calls trapFocus() and lockScroll() from @morphos/core while open, the same way Dialog does.

Styling example

.morphos-drawer-content {
  position: fixed;
  display: flex;
  flex-direction: column;
  padding: var(--morphos-space-4);
}

.morphos-drawer-content[data-side="right"] {
  top: 0;
  right: 0;
  bottom: 0;
  width: min(24rem, 100vw);
  animation: morphos-slide-in-right var(--morphos-transition-medium);
}

@keyframes morphos-slide-in-right {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}

On this page