Drawer
A panel that slides in from any edge of the screen with swipe-to-dismiss gestures. Supports left, right, top, and bottom orientations.
All sides
import { Drawer } from "@brijbyte/agentic-ui/drawer";
import { Button } from "@brijbyte/agentic-ui/button";
import { Drawer as BaseDrawer } from "@base-ui/react/drawer";
import type { DrawerSide } from "@brijbyte/agentic-ui/drawer";
import "@brijbyte/agentic-ui/drawer.css";
import "@brijbyte/agentic-ui/button.css";
const SIDES: DrawerSide[] = ["right", "left", "bottom", "top"];
export default function SidesDemo() {
return (
<div style={{ display: "flex", gap: "var(--space-2)", flexWrap: "wrap" }}>
{SIDES.map((side) => (
<Drawer
key={side}
side={side}
trigger={
<Button variant="outline" size="sm">
{side}
</Button>
}
title={`${side.charAt(0).toUpperCase() + side.slice(1)} drawer`}
description="Slides in from the edge. Swipe to dismiss."
footer={
<Button variant="soft" size="sm" render={<BaseDrawer.Close />}>
Done
</Button>
}
>
<p style={{ fontFamily: "var(--font-mono)", fontSize: "var(--font-size-sm)", color: "var(--color-secondary)", margin: 0 }}>
Content goes here. This drawer slides in from the <strong>{side}</strong> edge and supports swipe-to-dismiss.
</p>
</Drawer>
))}
</div>
);
}
Bottom sheet
import { Drawer } from "@brijbyte/agentic-ui/drawer";
import { Drawer as BaseDrawer } from "@base-ui/react/drawer";
import { Button } from "@brijbyte/agentic-ui/button";
import { Separator } from "@brijbyte/agentic-ui/separator";
import "@brijbyte/agentic-ui/drawer.css";
import "@brijbyte/agentic-ui/button.css";
import "@brijbyte/agentic-ui/separator.css";
const ACTIONS = ["Rename", "Duplicate", "Move to folder", "Download"];
export default function BottomSheetDemo() {
return (
<Drawer
side="bottom"
trigger={
<Button variant="outline" size="sm">
File options
</Button>
}
title="report-q4.pdf"
dismissible={false}
footer={
<Button variant="solid" tone="destructive" size="sm" render={<BaseDrawer.Close />}>
Delete file
</Button>
}
>
<div style={{ display: "flex", flexDirection: "column" }}>
{ACTIONS.map((action, i) => (
<div key={action}>
{i > 0 && <Separator />}
<button
type="button"
style={{
display: "block",
width: "100%",
padding: "var(--space-3) 0",
background: "none",
border: "none",
textAlign: "left",
fontFamily: "var(--font-mono)",
fontSize: "var(--font-size-sm)",
color: "var(--color-primary)",
cursor: "pointer",
}}
>
{action}
</button>
</div>
))}
</div>
</Drawer>
);
}
Composed: base-ui Root + styled parts
import { Drawer, Drawer as BaseDrawer } from "@base-ui/react/drawer";
import {
DrawerBackdrop,
DrawerViewport,
DrawerPopup,
DrawerContent,
DrawerTitle,
DrawerDescription,
DrawerClose,
DrawerFooter,
} from "@brijbyte/agentic-ui/drawer";
import { Button } from "@brijbyte/agentic-ui/button";
import "@brijbyte/agentic-ui/drawer.css";
import "@brijbyte/agentic-ui/button.css";
export default function ComposedDemo() {
return (
<Drawer.Root swipeDirection="right">
<Drawer.Trigger
render={
<Button variant="ghost" size="sm">
Open (composed)
</Button>
}
/>
<Drawer.Portal>
<DrawerBackdrop />
<DrawerViewport side="right">
<DrawerPopup side="right" style={{ position: "relative" }}>
<DrawerContent>
<DrawerTitle>Settings</DrawerTitle>
<DrawerDescription>Composed with raw base-ui Root and styled parts.</DrawerDescription>
<p
style={{
fontFamily: "var(--font-mono)",
fontSize: "var(--font-size-sm)",
color: "var(--color-secondary)",
margin: 0,
}}
>
You have full control over the base-ui Root behaviour while keeping all design-system styling via the styled parts.
</p>
<DrawerFooter>
<Button variant="outline" size="sm" render={<BaseDrawer.Close />}>
Close
</Button>
<Button variant="solid" size="sm">
Save
</Button>
</DrawerFooter>
</DrawerContent>
<DrawerClose aria-label="Close drawer" />
</DrawerPopup>
</DrawerViewport>
</Drawer.Portal>
</Drawer.Root>
);
}