Skip to Content
Dashflow Logo

Drawer Component

A comprehensive guide to using the Drawer component with examples, props, and best practices.


Overview

The Drawer component provides a slide-out panel interface for displaying content, navigation, and interactive elements. It's commonly used for sidebars, navigation menus, and any content that needs to be displayed in a slide-out panel.

Basic Usage

import { Drawer } from '@dashflowx/core'
export default function DrawerExample() {
return (
<Drawer
header={<div>Drawer Header</div>}
contentElement={<div>Drawer content goes here.</div>}
footer={<div>Drawer Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="drawer-1"
className="w-80"
/>
)
}

Preview:

Props

PropTypeDefaultDescription
headerJSX.Element-The header content of the drawer
contentElementJSX.Element-The main content of the drawer
footerJSX.Element-The footer content of the drawer
anchorOriginObject{ horizontal: 'right', vertical: 'top' }The position of the drawer
keystring-Unique key for the drawer
classNamestring-Additional CSS classes for the drawer
containerClassNamestring-Additional CSS classes for the container
headerClassNamestring-Additional CSS classes for the header
footerClassNamestring-Additional CSS classes for the footer

Anchor Origin Structure

interface AnchorOrigin {
horizontal: 'left' | 'right';
vertical: 'top' | 'bottom';
}

Examples

Basic Drawer

<Drawer
header={<div className="text-lg font-semibold">Settings</div>}
contentElement={
<div className="space-y-4">
<p>Drawer content goes here.</p>
</div>
}
footer={<div className="text-sm text-gray-500">Footer content</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="settings-drawer"
className="w-80"
/>

Preview:

Left Side Drawer

<Drawer
header={<div className="text-lg font-semibold">Navigation</div>}
contentElement={
<div className="space-y-2">
<div className="p-2 hover:bg-gray-100 rounded">Home</div>
<div className="p-2 hover:bg-gray-100 rounded">About</div>
<div className="p-2 hover:bg-gray-100 rounded">Contact</div>
</div>
}
footer={<div className="text-sm text-gray-500">Navigation Footer</div>}
anchorOrigin={{ horizontal: 'left', vertical: 'top' }}
key="nav-drawer"
className="w-64"
/>

Preview:

Right Side Drawer

<Drawer
header={<div className="text-lg font-semibold">Cart</div>}
contentElement={
<div className="space-y-4">
<div className="border-b pb-4">
<h3 className="font-medium">Cart Items</h3>
<p className="text-sm text-gray-500">3 items in cart</p>
</div>
<div className="space-y-2">
<div className="flex justify-between">
<span>Item 1</span>
<span>$10.00</span>
</div>
<div className="flex justify-between">
<span>Item 2</span>
<span>$15.00</span>
</div>
</div>
</div>
}
footer={
<div className="space-y-2">
<div className="flex justify-between font-semibold">
<span>Total</span>
<span>$25.00</span>
</div>
<button className="w-full bg-blue-600 text-white py-2 rounded">
Checkout
</button>
</div>
}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="cart-drawer"
className="w-96"
/>

Preview:

Custom Styled Drawer

<Drawer
header={<div className="text-lg font-semibold text-blue-600">Custom Styled</div>}
contentElement={
<div className="space-y-4">
<p>This drawer has custom styling.</p>
</div>
}
footer={<div className="text-sm text-blue-500">Custom Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="custom-drawer"
className="w-80 border-2 border-blue-500 rounded-l-xl"
/>

Preview:

Large Drawer

<Drawer
header={<div className="text-xl font-bold">Large Drawer</div>}
contentElement={
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold mb-2">Section 1</h3>
<p>This is a larger drawer with more content space.</p>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Section 2</h3>
<p>It can contain multiple sections and form elements.</p>
</div>
<div>
<h3 className="text-lg font-semibold mb-2">Section 3</h3>
<p>Perfect for complex forms and detailed content.</p>
</div>
</div>
}
footer={
<div className="flex space-x-2">
<button className="flex-1 bg-gray-200 text-gray-800 py-2 rounded">
Cancel
</button>
<button className="flex-1 bg-blue-600 text-white py-2 rounded">
Save
</button>
</div>
}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="large-drawer"
className="w-96"
/>

Preview:

Common Use Cases

<Drawer
header={
<div className="flex items-center space-x-2">
<span className="text-lg font-semibold">Menu</span>
</div>
}
contentElement={
<div className="space-y-1">
<div className="p-3 hover:bg-gray-100 rounded cursor-pointer">
<div className="flex items-center space-x-3">
<span>🏠</span>
<span>Dashboard</span>
</div>
</div>
<div className="p-3 hover:bg-gray-100 rounded cursor-pointer">
<div className="flex items-center space-x-3">
<span>📊</span>
<span>Analytics</span>
</div>
</div>
<div className="p-3 hover:bg-gray-100 rounded cursor-pointer">
<div className="flex items-center space-x-3">
<span>👥</span>
<span>Users</span>
</div>
</div>
<div className="p-3 hover:bg-gray-100 rounded cursor-pointer">
<div className="flex items-center space-x-3">
<span>⚙️</span>
<span>Settings</span>
</div>
</div>
</div>
}
footer={
<div className="text-sm text-gray-500">
Version 1.0.0
</div>
}
anchorOrigin={{ horizontal: 'left', vertical: 'top' }}
key="nav-sidebar"
className="w-64"
/>

Shopping Cart

<Drawer
header={
<div className="flex items-center justify-between">
<span className="text-lg font-semibold">Shopping Cart</span>
<span className="text-sm text-gray-500">3 items</span>
</div>
}
contentElement={
<div className="space-y-4">
<div className="border-b pb-4">
<div className="flex items-center space-x-3">
<div className="w-16 h-16 bg-gray-200 rounded"></div>
<div className="flex-1">
<h3 className="font-medium">Product Name</h3>
<p className="text-sm text-gray-500">Size: M, Color: Blue</p>
<p className="text-sm font-semibold">$29.99</p>
</div>
<div className="flex items-center space-x-2">
<button className="w-6 h-6 bg-gray-200 rounded">-</button>
<span>1</span>
<button className="w-6 h-6 bg-gray-200 rounded">+</button>
</div>
</div>
</div>
<div className="border-b pb-4">
<div className="flex items-center space-x-3">
<div className="w-16 h-16 bg-gray-200 rounded"></div>
<div className="flex-1">
<h3 className="font-medium">Another Product</h3>
<p className="text-sm text-gray-500">Size: L, Color: Red</p>
<p className="text-sm font-semibold">$39.99</p>
</div>
<div className="flex items-center space-x-2">
<button className="w-6 h-6 bg-gray-200 rounded">-</button>
<span>2</span>
<button className="w-6 h-6 bg-gray-200 rounded">+</button>
</div>
</div>
</div>
</div>
}
footer={
<div className="space-y-3">
<div className="flex justify-between text-lg font-semibold">
<span>Total</span>
<span>$109.97</span>
</div>
<button className="w-full bg-blue-600 text-white py-3 rounded font-medium">
Proceed to Checkout
</button>
</div>
}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="shopping-cart"
className="w-96"
/>

Settings Panel

<Drawer
header={
<div className="flex items-center space-x-2">
<span className="text-lg font-semibold">Settings</span>
</div>
}
contentElement={
<div className="space-y-6">
<div>
<h3 className="text-sm font-semibold text-gray-500 uppercase tracking-wide mb-3">
Account
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm">Email Notifications</span>
<input type="checkbox" className="rounded" defaultChecked />
</div>
<div className="flex items-center justify-between">
<span className="text-sm">SMS Notifications</span>
<input type="checkbox" className="rounded" />
</div>
</div>
</div>
<div>
<h3 className="text-sm font-semibold text-gray-500 uppercase tracking-wide mb-3">
Privacy
</h3>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm">Profile Visibility</span>
<select className="text-sm border rounded px-2 py-1">
<option>Public</option>
<option>Private</option>
</select>
</div>
<div className="flex items-center justify-between">
<span className="text-sm">Data Sharing</span>
<input type="checkbox" className="rounded" />
</div>
</div>
</div>
</div>
}
footer={
<div className="flex space-x-2">
<button className="flex-1 bg-gray-200 text-gray-800 py-2 rounded text-sm">
Reset
</button>
<button className="flex-1 bg-blue-600 text-white py-2 rounded text-sm">
Save Changes
</button>
</div>
}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="settings-panel"
className="w-80"
/>

Filter Panel

<Drawer
header={
<div className="flex items-center justify-between">
<span className="text-lg font-semibold">Filters</span>
<button className="text-sm text-blue-600">Clear All</button>
</div>
}
contentElement={
<div className="space-y-6">
<div>
<h3 className="text-sm font-semibold mb-3">Price Range</h3>
<div className="space-y-2">
<input
type="range"
min="0"
max="1000"
className="w-full"
/>
<div className="flex justify-between text-sm text-gray-500">
<span>$0</span>
<span>$1000</span>
</div>
</div>
</div>
<div>
<h3 className="text-sm font-semibold mb-3">Category</h3>
<div className="space-y-2">
<label className="flex items-center">
<input type="checkbox" className="rounded mr-2" />
<span className="text-sm">Electronics</span>
</label>
<label className="flex items-center">
<input type="checkbox" className="rounded mr-2" />
<span className="text-sm">Clothing</span>
</label>
<label className="flex items-center">
<input type="checkbox" className="rounded mr-2" />
<span className="text-sm">Books</span>
</label>
</div>
</div>
<div>
<h3 className="text-sm font-semibold mb-3">Brand</h3>
<div className="space-y-2">
<label className="flex items-center">
<input type="checkbox" className="rounded mr-2" />
<span className="text-sm">Brand A</span>
</label>
<label className="flex items-center">
<input type="checkbox" className="rounded mr-2" />
<span className="text-sm">Brand B</span>
</label>
</div>
</div>
</div>
}
footer={
<div className="flex space-x-2">
<button className="flex-1 bg-gray-200 text-gray-800 py-2 rounded text-sm">
Reset
</button>
<button className="flex-1 bg-blue-600 text-white py-2 rounded text-sm">
Apply Filters
</button>
</div>
}
anchorOrigin={{ horizontal: 'left', vertical: 'top' }}
key="filter-panel"
className="w-80"
/>

Best Practices

1. Clear Header Content

Use clear and descriptive header content.

// ✅ Good - Clear header
<Drawer
header={<div className="text-lg font-semibold">User Settings</div>}
contentElement={<div>Settings content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="settings"
className="w-80"
/>
// ❌ Avoid - Unclear header
<Drawer
header={<div>Settings</div>}
contentElement={<div>Content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="settings"
className="w-80"
/>

2. Appropriate Drawer Size

Use appropriate drawer sizes for different content types.

// ✅ Good - Appropriate sizing
<Drawer
header={<div>Navigation</div>}
contentElement={<div>Navigation content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'left', vertical: 'top' }}
key="nav"
className="w-64" // Narrow for navigation
/>
<Drawer
header={<div>Settings</div>}
contentElement={<div>Settings content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="settings"
className="w-96" // Wider for forms
/>

3. Consistent Positioning

Use consistent positioning for similar drawer types.

// ✅ Good - Consistent positioning
const navigationDrawer = (
<Drawer
anchorOrigin={{ horizontal: 'left', vertical: 'top' }}
// ... other props
/>
);
const settingsDrawer = (
<Drawer
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
// ... other props
/>
);

4. Accessible Implementation

Ensure drawers are accessible to all users.

// ✅ Good - Accessible
<Drawer
header={<div role="heading" aria-level="2">Settings</div>}
contentElement={<div role="main">Settings content</div>}
footer={<div role="contentinfo">Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="settings"
className="w-80"
/>

5. Proper Content Structure

Structure drawer content logically.

// ✅ Good - Proper structure
<Drawer
header={<div>User Profile</div>}
contentElement={
<div className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">Name</label>
<input type="text" className="w-full border rounded px-3 py-2" />
</div>
<div>
<label className="block text-sm font-medium mb-2">Email</label>
<input type="email" className="w-full border rounded px-3 py-2" />
</div>
</div>
}
footer={
<div className="flex space-x-2">
<button>Cancel</button>
<button>Save</button>
</div>
}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="profile"
className="w-80"
/>

Customization

Custom Styling

You can customize the drawer appearance using CSS classes:

<Drawer
header={<div>Custom Styled</div>}
contentElement={<div>Custom content</div>}
footer={<div>Custom footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="custom"
className="w-80 border-2 border-purple-500 rounded-l-xl"
/>

Different Themes

Use different themes for different contexts:

// Light theme
<Drawer
header={<div>Light Theme</div>}
contentElement={<div>Content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="light"
className="w-80 bg-white border-gray-200"
/>
// Dark theme
<Drawer
header={<div>Dark Theme</div>}
contentElement={<div>Content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="dark"
className="w-80 bg-gray-900 border-gray-700 text-white"
/>

Size Variations

Use different sizes for different content types:

// Small drawer
<Drawer
header={<div>Small</div>}
contentElement={<div>Simple content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="small"
className="w-64"
/>
// Large drawer
<Drawer
header={<div>Large</div>}
contentElement={<div>Complex content</div>}
footer={<div>Footer</div>}
anchorOrigin={{ horizontal: 'right', vertical: 'top' }}
key="large"
className="w-96"
/>

Advanced Usage

Dynamic Content

Load drawer content dynamically:

const [drawerContent, setDrawerContent] = useState(null);
const openDrawer = (type: string) => {
switch (type) {
case 'settings':
setDrawerContent(settingsContent);
break;
case 'profile':
setDrawerContent(profileContent);
break;
default:
setDrawerContent(defaultContent);
}
};

Drawer State Management

Manage drawer state effectively:

const [isOpen, setIsOpen] = useState(false);
const [drawerType, setDrawerType] = useState('');
const openDrawer = (type: string) => {
setDrawerType(type);
setIsOpen(true);
};
const closeDrawer = () => {
setIsOpen(false);
setDrawerType('');
};

Multiple Drawers

Handle multiple drawers in the same application:

const [activeDrawer, setActiveDrawer] = useState(null);
const openDrawer = (drawerId: string) => {
setActiveDrawer(drawerId);
};
const closeDrawer = () => {
setActiveDrawer(null);
};
  • Modal: For modal overlays
  • Popover: For popup content
  • Sheet: For slide-out content
  • Sidebar: For navigation sidebars
  • Panel: For content panels

API Reference

For the complete API reference and advanced usage patterns, see the Drawer API documentation.

Edit this page on GitHub