Drawer
A panel that slides in from the edge of the screen. Use for forms, details, or task panels.
Import
Section titled “Import”import { Drawer } from 'asterui'Examples
Section titled “Examples”Basic Drawer
Simple drawer from the right side.
import { Drawer, Button } from 'asterui'
import { useState } from 'react'
function App() {
const [open, setOpen] = useState(false)
return (
<Button color="primary" onClick={() => setOpen(true)}>
Open Drawer
</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
title="Basic Drawer"
>
<p>Drawer content goes here.</p>
</Drawer>
)
}
export default App Placement
Drawer can slide in from any direction.
import { Drawer, Button, Space } from 'asterui'
import { useState } from 'react'
function App() {
const [placement, setPlacement] = useState<'left' | 'right' | 'top' | 'bottom'>('right')
const [open, setOpen] = useState(false)
const showDrawer = (p: typeof placement) => {
setPlacement(p)
setOpen(true)
}
return (
<Space direction="horizontal" size="sm" wrap>
<Button onClick={() => showDrawer('left')}>Left</Button>
<Button onClick={() => showDrawer('right')}>Right</Button>
<Button onClick={() => showDrawer('top')}>Top</Button>
<Button onClick={() => showDrawer('bottom')}>Bottom</Button>
</Space>
<Drawer
open={open}
onClose={() => setOpen(false)}
placement={placement}
title={`${placement.charAt(0).toUpperCase() + placement.slice(1)} Drawer`}
>
<p>This drawer slides in from the {placement}.</p>
</Drawer>
)
}
export default App With Footer
Drawer with action buttons in footer.
import { Drawer, Button, Space } from 'asterui'
import { useState } from 'react'
function App() {
const [open, setOpen] = useState(false)
return (
<Button color="primary" onClick={() => setOpen(true)}>
Open Drawer
</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
title="Edit Profile"
footer={
<Space direction="horizontal" size="sm">
<Button onClick={() => setOpen(false)}>Cancel</Button>
<Button color="primary" onClick={() => setOpen(false)}>
Save
</Button>
</Space>
}
>
<p>Form content would go here...</p>
</Drawer>
)
}
export default App Extra Header Content
Drawer with extra actions in the header.
import { Drawer, Button, Space } from 'asterui'
import { useState } from 'react'
function App() {
const [open, setOpen] = useState(false)
return (
<Button color="primary" onClick={() => setOpen(true)}>
Open Drawer
</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
title="User Details"
extra={
<Space size="xs">
<Button size="sm" variant="ghost">Edit</Button>
<Button size="sm" variant="ghost">Delete</Button>
</Space>
}
>
<p>User information displayed here.</p>
</Drawer>
)
}
export default App Preset Sizes
Default (378px) and large (736px) preset sizes.
import { Drawer, Button, Space } from 'asterui'
import { useState } from 'react'
function App() {
const [size, setSize] = useState<'default' | 'large'>('default')
const [open, setOpen] = useState(false)
const showDrawer = (s: typeof size) => {
setSize(s)
setOpen(true)
}
return (
<Space direction="horizontal" size="sm">
<Button onClick={() => showDrawer('default')}>Default (378px)</Button>
<Button onClick={() => showDrawer('large')}>Large (736px)</Button>
</Space>
<Drawer
open={open}
onClose={() => setOpen(false)}
title={`${size.charAt(0).toUpperCase() + size.slice(1)} Drawer`}
size={size}
>
<p>This drawer uses the {size} preset size.</p>
</Drawer>
)
}
export default App Loading State
Drawer with skeleton loading state.
import { Drawer, Button } from 'asterui'
import { useState, useEffect } from 'react'
function App() {
const [open, setOpen] = useState(false)
const [loading, setLoading] = useState(true)
useEffect(() => {
if (open) {
setLoading(true)
const timer = setTimeout(() => setLoading(false), 1500)
return () => clearTimeout(timer)
}
}, [open])
return (
<Button color="primary" onClick={() => setOpen(true)}>
Load Data
</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
title="User Profile"
loading={loading}
>
<div className="space-y-4">
<p><strong>Name:</strong> John Doe</p>
<p><strong>Email:</strong> john@example.com</p>
<p><strong>Role:</strong> Administrator</p>
</div>
</Drawer>
)
}
export default App Nested Drawers
Multiple drawers with push behavior.
import { Drawer, Button } from 'asterui'
import { useState } from 'react'
function App() {
const [open1, setOpen1] = useState(false)
const [open2, setOpen2] = useState(false)
return (
<Button color="primary" onClick={() => setOpen1(true)}>
Open First Drawer
</Button>
<Drawer
open={open1}
onClose={() => setOpen1(false)}
title="First Drawer"
push={{ distance: 180 }}
>
<p>This is the first drawer.</p>
<Button color="secondary" onClick={() => setOpen2(true)}>
Open Second Drawer
</Button>
<Drawer
open={open2}
onClose={() => setOpen2(false)}
title="Second Drawer"
width={400}
>
<p>This is a nested drawer.</p>
<p>Notice how the first drawer pushed back.</p>
</Drawer>
</Drawer>
)
}
export default App No Mask
Drawer without backdrop overlay.
import { Drawer, Button } from 'asterui'
import { useState } from 'react'
function App() {
const [open, setOpen] = useState(false)
return (
<Button color="primary" onClick={() => setOpen(true)}>
Open Drawer
</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
title="No Mask Drawer"
mask={false}
>
<p>This drawer has no backdrop overlay.</p>
<p>You can still interact with the page behind it.</p>
</Drawer>
)
}
export default App Drawer
Section titled “Drawer”| Property | Description | Type | Default |
|---|---|---|---|
children | Drawer content | React.ReactNode | - |
open | Controlled open state | boolean | false |
onClose | Close handler | (e?: React.MouseEvent | React.KeyboardEvent) => void | - |
afterOpenChange | Callback after open/close animation completes | (open: boolean) => void | - |
title | Drawer title | React.ReactNode | - |
placement | Drawer position | 'left' | 'right' | 'top' | 'bottom' | 'right' |
size | Preset size (378px or 736px) or custom number | 'default' | 'large' | number | 'default' |
width | Custom width (overrides size for left/right) | string | number | - |
height | Custom height (overrides size for top/bottom) | string | number | - |
closable | Show close button | boolean | true |
mask | Show overlay mask | boolean | true |
maskClosable | Close on mask click | boolean | true |
keyboard | Close on ESC key | boolean | true |
footer | Footer content | React.ReactNode | - |
extra | Extra content in header (right side) | React.ReactNode | - |
loading | Show loading skeleton | boolean | false |
destroyOnClose | Destroy content when closed | boolean | false |
forceRender | Pre-render content (keep in DOM when closed) | boolean | false |
push | Nested drawer push behavior | boolean | { distance: number } | { distance: 180 } |
zIndex | z-index of drawer | number | 1000 |
className | CSS class for drawer panel | string | - |