Skip to main content
The Drawer component provides a sliding panel that appears from the edge of the screen, useful for navigation, filters, or additional content.

Basic Usage

import reflex_ui as ui

ui.drawer(
    trigger=ui.button("Open Drawer"),
    title="Drawer Title",
    description="Drawer description",
    content="Main content"
)

Props Reference

trigger
Component
Component that opens the drawer when clicked
title
str | Component
Drawer heading
description
str | Component
Descriptive text below the title
content
str | Component
Main drawer content

Direction

direction
Literal['top', 'bottom', 'left', 'right']
default:"right"
Which edge the drawer slides from
ui.drawer(
    trigger=ui.button("Open Left"),
    direction="left",
    content="Slides from left"
)

ui.drawer(
    trigger=ui.button("Open Bottom"),
    direction="bottom",
    content="Slides from bottom"
)

Controlled State

class State(rx.State):
    drawer_open: bool = False

ui.drawer(
    trigger=ui.button("Open"),
    content="Controlled drawer",
    open=State.drawer_open,
    on_open_change=State.set_drawer_open
)
open
bool | Var[bool]
Whether drawer is open (controlled)
default_open
bool
default:"False"
Initial open state (uncontrolled)
on_open_change
EventHandler[bool]
Event fired when drawer opens or closes
on_animation_end
EventHandler[bool]
Event fired after animation completes
modal
bool
default:"True"
  • True: Blocks interaction with page, shows overlay
  • False: Allows interaction with page behind drawer
ui.drawer(
    trigger=ui.button("Non-Modal"),
    content="You can still interact with the page",
    modal=False
)

Dismissible

dismissible
bool
default:"True"
Whether clicking outside or dragging closes the drawer
ui.drawer(
    trigger=ui.button("Must Close Explicitly"),
    content="Cannot close by clicking outside",
    dismissible=False
)

Drag Behavior

handle_only
bool
default:"False"
When True, dragging only works on the handle element
ui.drawer.root(
    ui.drawer.trigger(render_=ui.button("Open")),
    ui.drawer.portal(
        ui.drawer.overlay(),
        ui.drawer.content(
            ui.drawer.handle(),  # Drag handle
            ui.drawer.title("Title"),
            "Content"
        )
    ),
    handle_only=True
)

Snap Points

snap_points
list[str | float]
Snap positions as percentages or pixel values (e.g., [0.25, 0.5, 1])
active_snap_point
int
Currently active snap point index
ui.drawer(
    trigger=ui.button("Open"),
    content="Drawer with snap points",
    snap_points=[0.4, 0.7, 1],
    direction="bottom"
)

Compositional API

ui.drawer.root(
    ui.drawer.trigger(
        render_=ui.button("Menu")
    ),
    ui.drawer.portal(
        ui.drawer.overlay(),
        ui.drawer.content(
            ui.drawer.title("Navigation"),
            ui.drawer.description("Site menu"),
            rx.el.nav(
                # navigation items
            ),
            ui.drawer.close(
                render_=ui.button("Close")
            )
        )
    ),
    direction="left"
)

Drawer Components

drawer.root

Container for all drawer parts.
ui.drawer.root(
    # child components
    direction="right",
    modal=True
)

drawer.trigger

Button that opens the drawer.
ui.drawer.trigger(
    render_=ui.button("Open Menu")
)

drawer.portal

Portals the drawer to document body.
ui.drawer.portal(
    ui.drawer.overlay(),
    ui.drawer.content(...)
)

drawer.overlay

Dark overlay behind drawer (when modal).
ui.drawer.overlay()  # Auto-styled

drawer.content

Main drawer panel.
ui.drawer.content(
    ui.drawer.title("Title"),
    "Content here"
)

drawer.title

Accessible heading for the drawer.
ui.drawer.title("Drawer Title")

drawer.description

Accessible description.
ui.drawer.description("Additional info")

drawer.close

Button to close the drawer.
ui.drawer.close(
    render_=ui.button("Done")
)

drawer.handle

Drag handle for mobile-friendly interaction.
ui.drawer.handle()  # Visual drag indicator

Styling Classes

Access predefined styles via ui.drawer.class_names:
  • ROOT: Root element (empty by default)
  • TRIGGER: Trigger element (empty by default)
  • PORTAL: Portal element (empty by default)
  • CONTENT: Drawer panel with border and background
  • OVERLAY: Semi-transparent backdrop
  • CLOSE: Close button (empty by default)
  • TITLE: Large semibold heading
  • DESCRIPTION: Secondary text
  • HANDLE: Drag handle (empty by default)

Container

container
str
DOM element to render drawer into (default: document.body)

Input Repositioning

reposition_inputs
bool
default:"True"
Automatically repositions inputs when drawer opens on mobile

Library

The drawer component uses the [email protected] library, which provides smooth, gesture-based drawer interactions.

Accessibility

  • Keyboard accessible (Escape to close)
  • Focus management
  • ARIA attributes
  • Screen reader support
  • Touch and mouse drag support

Implementation Details

From source code at reflex_ui/components/base/drawer.py:220:
  • Built on Vaul library (vaul-base package)
  • High-level wrapper creates complete structure
  • Auto-includes overlay and portal
  • Fixed positioning on right side by default
  • Max width of 24rem (384px)
  • Full height and responsive design

Build docs developers (and LLMs) love