Drawer
drawerSlides contextual or task content from any screen edge with modal focus management and a localized optional close button.
Usage
Basic usage
By default, it slides in from the right side; Esc / click mask / close button can be retracted, and the focus is locked in the drawer.
<Drawer>
<DrawerTrigger render={<Button variant="outline">Open drawer</Button>} />
<DrawerContent
title="Settings Panel"
description="Adjust your preferences here."
footer={
<>
<DrawerClose render={<Button variant="outline">Cancel</Button>} />
<DrawerClose render={<Button>Save</Button>} />
</>
}
>
{/* Text content */}
</DrawerContent>
</Drawer>Welt direction
side controls the welt orientation and sliding direction: left / right are side vertical drawers, top / bottom are horizontal drawers.
<>
<Drawer>
<DrawerTrigger render={<Button variant="outline">Left</Button>} />
<DrawerContent side="left" title="Left drawer" />
</Drawer>
<Drawer>
<DrawerTrigger render={<Button variant="outline">Bottom</Button>} />
<DrawerContent side="bottom" title="Bottom Drawer" />
</Drawer>
</>Long content scrolling + bottoming operation area
The text scrolls independently when the text is too long. footer is always visible at the bottom and is not squeezed out by the content.
<Drawer>
<DrawerTrigger render={<Button variant="outline">Open</Button>} />
<DrawerContent
side="right"
title="Settings Panel"
footer={
<>
<DrawerClose render={<Button variant="outline">Cancel</Button>} />
<DrawerClose render={<Button>Save</Button>} />
</>
}
>
{/* A large number of configuration items, the text area automatically scrolls */}
</DrawerContent>
</Drawer>When to use
Use Drawer for a panel that slides from a screen edge, such as filters, details, a form, or mobile navigation. Its body scrolls independently while actions remain pinned. Use Dialog for a centered overlay, AlertDialog for a forced decision, or Popover for a small anchored surface.
Import
import { Drawer, DrawerTrigger, DrawerClose, DrawerContent, drawerVariants } from "@hulianui/ui"Props
Drawer forwards Base UI Dialog Root props such as open, defaultOpen, and onOpenChange. DrawerTrigger and DrawerClose support render. DrawerContent adds HulianUI styling:
| Name | Type | Default | Description |
|---|---|---|---|
DrawerContent.side | "left" | "right" | "top" | "bottom" | "right" | Attached edge and corresponding slide direction. |
DrawerContent.container | Element | Ref | — | Local portal target. The drawer uses absolute positioning inside it; the target needs position:relative and overflow-hidden. Useful for phone-frame previews. |
DrawerContent.showClose | boolean | true | Whether to render the built-in top-right close button. |
DrawerContent.closeLabel | string | Locale value | Accessible name for the built-in close button; defaults to locale.drawer.close. |
DrawerContent.className | string | — | Content-container class name. |
Events
| Event | Type | Description |
|---|---|---|
Drawer.onOpenChange | (open: boolean) => void | Called when the open state changes; forwarded to Base UI Dialog Root. |
Slots
| Slot | Type | Description |
|---|---|---|
DrawerContent.title | ReactNode | Optional Dialog.Title and accessible label. |
DrawerContent.description | ReactNode | Supporting copy. |
DrawerContent.footer | ReactNode | Pinned action area with a divider, kept visible while the body scrolls. |
DrawerContent.children | ReactNode | Main body content. |
Example
<Drawer>
<DrawerTrigger render={<Button variant="outline">Open drawer</Button>} />
<DrawerContent
side="right"
title="Settings"
description="Escape, the overlay, or a close control dismisses the drawer; focus remains inside."
footer={<><DrawerClose render={<Button variant="outline">Cancel</Button>} /><DrawerClose render={<Button>Save</Button>} /></>}
>
{/* Long body content scrolls while the footer remains pinned */}
</DrawerContent>
</Drawer>Usage guidelines
- Base UI rc.0 has no standalone Drawer primitive. This component restyles Dialog's Portal, Backdrop, and Popup and uses
translateX/Yby side. Dialog has no Positioner, so Tooltip and Popover positioning assumptions do not apply. See [[base-ui-dialog-drawer-side-slide-via-transform]]. - Put Cancel, Save, and Close controls in
footer; actions at the end of the body scroll out of view. - With
container, the target must useposition:relativeandoverflow-hiddenor the drawer and overlay escape the local frame.
Close button
DrawerContent renders a top-right close button by default through showClose. Its accessible name comes from closeLabel or the locale's drawer.close value. Display-only drawers such as navigation or detail panels may have no footer; previously their only visible escape was the overlay, keyboard users had only Escape, and screen-reader users could not discover a Close control inside the panel (hulianui/hulian#63). The button is absolutely positioned and does not consume layout space.
Related
Dialog · Modal · AlertDialog · Popover · Tooltip · HoverCard
Playground
<Drawer>
<DrawerTrigger render={<Button>Open</Button>} />
<DrawerContent
side="right"
title="Settings Panel"
footer={<>
<DrawerClose render={<Button variant="outline">Cancel</Button>} />
<DrawerClose render={<Button>Save</Button>} />
</>}
>
{/* Text (extremely long automatic scrolling, footer nail bottom) */}
</DrawerContent>
</Drawer>