Drawer
A slide-in panel component with four positions, focus trapping, backdrop, and customizable header/footer.
Basic Usage
Default Drawer
A right-side drawer with header and close button.
import { Drawer, Button } from 'fluxo-ui';
const [open, setOpen] = useState(false);
<Button onClick={() => setOpen(true)}>Open Drawer</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
header="Drawer Title"
>
<p>Drawer body content goes here.</p>
</Drawer>Positions
Use the position prop to slide the drawer in from any edge.
Drawer Positions
Drawers can slide in from any edge: left, right, top, or bottom.
import { Drawer } from 'fluxo-ui';
import type { DrawerPosition } from 'fluxo-ui';
<Drawer open={open} onClose={close} position="left" header="Left Drawer">
...
</Drawer>
<Drawer open={open} onClose={close} position="top" header="Top Drawer" size="300px">
...
</Drawer>
<Drawer open={open} onClose={close} position="bottom" header="Bottom Drawer" size="300px">
...
</Drawer>Bottom Sheet
Set variant="sheet" with position="bottom" (or "top") to get a drag handle, rounded corners, snap points, and drag-to-dismiss — ideal for mobile flows.
Snap points
A bottom sheet with three snap points (30%, 60%, 90% of viewport). Drag the handle up or down — the sheet settles on the nearest snap.
import { Drawer } from 'fluxo-ui';
const [open, setOpen] = useState(false);
<Drawer
open={open}
onClose={() => setOpen(false)}
position="bottom"
variant="sheet"
snapPoints={[0.3, 0.6, 0.9]}
initialSnap={1}
title="Select an option"
>
{/* sheet body */}
</Drawer>Drag-to-dismiss
Sheet without snap points — drag down past 40% of its height or fast-swipe down to dismiss.
Top sheet
Sheets aren't limited to the bottom — the same drag/snap behavior works with position='top'.
Custom Content
Add a header and footer to create structured drawer layouts with action buttons.
Custom Header & Footer
A drawer with a form, custom header, and action buttons in the footer.
import { Drawer, Button, TextInput } from 'fluxo-ui';
<Drawer
open={open}
onClose={() => setOpen(false)}
header="Edit Profile"
footer={
<div className="flex gap-2 justify-end">
<Button variant="default" onClick={() => setOpen(false)}>Cancel</Button>
<Button variant="primary" onClick={handleSave}>Save</Button>
</div>
}
size="480px"
>
<form className="space-y-4">
<TextInput label="Full Name" value={name} onChange={setName} />
<TextInput label="Email" value={email} onChange={setEmail} />
</form>
</Drawer>Import
import { Drawer } from 'fluxo-ui';
import type { DrawerProps, DrawerPosition } from 'fluxo-ui';Props
openreqbooleanWhether the drawer is visible.
openreqbooleanWhether the drawer is visible.
onClosereq() => voidCalled when the drawer should close.
onClosereq() => voidCalled when the drawer should close.
position'left' | 'right' | 'top' | 'bottom'"'right'"Edge from which the drawer slides in.
position'left' | 'right' | 'top' | 'bottom'"'right'"Edge from which the drawer slides in.
sizestring"'400px'"Width (horizontal) or height (vertical) of the drawer. Ignored when snapPoints is provided.
sizestring"'400px'"Width (horizontal) or height (vertical) of the drawer. Ignored when snapPoints is provided.
variant'panel' | 'sheet'Visual variant. 'sheet' adds rounded top corners, drag handle, and drag-to-dismiss behavior — ideal for mobile bottom sheets. Auto-resolves to 'sheet' when position='bottom' and any sheet feature is set.
variant'panel' | 'sheet'Visual variant. 'sheet' adds rounded top corners, drag handle, and drag-to-dismiss behavior — ideal for mobile bottom sheets. Auto-resolves to 'sheet' when position='bottom' and any sheet feature is set.
showDragHandlebooleanShow a drag handle at the top of the drawer. Defaults to true for sheet variant on top/bottom positions.
showDragHandlebooleanShow a drag handle at the top of the drawer. Defaults to true for sheet variant on top/bottom positions.
draggablebooleanEnable drag-to-dismiss / drag-between-snap-points gestures. Defaults to true for sheet variant on top/bottom positions.
draggablebooleanEnable drag-to-dismiss / drag-between-snap-points gestures. Defaults to true for sheet variant on top/bottom positions.
snapPoints(number | string)[]List of snap point heights (e.g. [0.3, 0.6, 0.9] or ['30%', '60vh', '600px']). Numeric <=1 is treated as a viewport ratio.
snapPoints(number | string)[]List of snap point heights (e.g. [0.3, 0.6, 0.9] or ['30%', '60vh', '600px']). Numeric <=1 is treated as a viewport ratio.
initialSnapnumber"0"Index of the snap point used when the drawer opens.
initialSnapnumber"0"Index of the snap point used when the drawer opens.
onSnapChange(index: number) => voidCalled when the drawer settles on a new snap point.
onSnapChange(index: number) => voidCalled when the drawer settles on a new snap point.
roundedbooleanRound the corners that face the viewport center. Defaults to true for the sheet variant.
roundedbooleanRound the corners that face the viewport center. Defaults to true for the sheet variant.
backdropboolean"true"Show a dark backdrop behind the drawer.
backdropboolean"true"Show a dark backdrop behind the drawer.
pushContentboolean"false"Push the main content instead of overlaying.
pushContentboolean"false"Push the main content instead of overlaying.
pushContentSelectorstringCSS selector for the element to push when pushContent is enabled. Defaults to '#root' or the first body child.
pushContentSelectorstringCSS selector for the element to push when pushContent is enabled. Defaults to '#root' or the first body child.
closeOnEscapeboolean"true"Close drawer on Escape key press.
closeOnEscapeboolean"true"Close drawer on Escape key press.
closeOnBackdropClickboolean"true"Close drawer when clicking the backdrop.
closeOnBackdropClickboolean"true"Close drawer when clicking the backdrop.
titlestringPlain-text title rendered as the drawer header (when no custom header is supplied) and used as the dialog's accessible name.
titlestringPlain-text title rendered as the drawer header (when no custom header is supplied) and used as the dialog's accessible name.
ariaLabelstringAccessible name for the dialog. Use when there's no visible title.
ariaLabelstringAccessible name for the dialog. Use when there's no visible title.
ariaLabelledBystringID of an element that labels the dialog. Overrides ariaLabel/title when set.
ariaLabelledBystringID of an element that labels the dialog. Overrides ariaLabel/title when set.
headerReactNodeHeader content. When provided, shows a header bar with close button.
headerReactNodeHeader content. When provided, shows a header bar with close button.
footerReactNodeFooter content rendered at the bottom.
footerReactNodeFooter content rendered at the bottom.
childrenreqReactNodeMain body content of the drawer.
childrenreqReactNodeMain body content of the drawer.
classNamestringAdditional CSS class for the drawer panel.
classNamestringAdditional CSS class for the drawer panel.
Features
Four Positions
Slide in from left, right, top, or bottom with smooth CSS transitions.
Focus Trap
Tab key cycles through focusable elements within the drawer.
Push Content
Optionally push main content aside instead of overlaying.
Header & Footer
Optional header with close button and footer for action buttons.
Backdrop Control
Toggle backdrop visibility and close-on-click behavior.
Accessibility
ARIA modal role, focus restoration, and escape key handling.