React drawer component with slide-out navigation panels, animations, and flexible positioning
npx @tessl/cli install tessl/npm-rc-drawer@8.0.00
# RC-Drawer
1
2
## Overview
3
4
RC-Drawer is a comprehensive React component for creating slide-out navigation panels and sidebar interfaces. It provides smooth animations, flexible positioning, keyboard support, focus management, and accessibility features. The component supports four placement positions, nested drawer management with push/pull behavior, and extensive customization options for modern React applications.
5
6
## Package Information
7
8
- **Package Name**: rc-drawer
9
- **Package Type**: npm
10
- **Language**: TypeScript
11
- **Installation**: `npm install rc-drawer`
12
13
## Core Imports
14
15
```typescript
16
import Drawer from "rc-drawer";
17
import type { DrawerProps } from "rc-drawer";
18
```
19
20
For CommonJS:
21
22
```javascript
23
const Drawer = require("rc-drawer");
24
```
25
26
## Basic Usage
27
28
```typescript
29
import React, { useState } from "react";
30
import Drawer from "rc-drawer";
31
32
function App() {
33
const [open, setOpen] = useState(false);
34
35
return (
36
<div>
37
<button onClick={() => setOpen(true)}>Open Drawer</button>
38
<Drawer
39
open={open}
40
onClose={() => setOpen(false)}
41
placement="right"
42
width={300}
43
>
44
<h2>Drawer Content</h2>
45
<p>This is the drawer content</p>
46
</Drawer>
47
</div>
48
);
49
}
50
```
51
52
## Architecture
53
54
RC-Drawer is built with several key architectural components:
55
56
- **Portal Integration**: Uses `@rc-component/portal` for rendering outside the React component tree
57
- **Motion System**: Leverages `rc-motion` for smooth slide animations and transitions
58
- **Context System**: Provides context for nested drawer management and ref sharing
59
- **Focus Management**: Automatic focus handling with focus trapping and restoration
60
- **Accessibility**: Full ARIA support with proper dialog semantics and keyboard navigation
61
62
## Capabilities
63
64
### Main Drawer Component
65
66
The primary React component for creating drawer interfaces with comprehensive configuration options.
67
68
```typescript { .api }
69
/**
70
* Main drawer component that renders a slide-out panel with backdrop
71
*/
72
declare const Drawer: React.FC<DrawerProps>;
73
74
interface DrawerProps extends
75
Omit<DrawerPopupProps, 'prefixCls' | 'inline'>,
76
DrawerPanelEvents,
77
DrawerPanelAccessibility {
78
/** CSS class prefix (default: 'rc-drawer') */
79
prefixCls?: string;
80
/** Controls drawer visibility */
81
open?: boolean;
82
/** Close event handler */
83
onClose?: (e: React.MouseEvent | React.KeyboardEvent) => void;
84
/** Whether to destroy drawer content when closed */
85
destroyOnClose?: boolean;
86
/** Portal container selector/element */
87
getContainer?: PortalProps['getContainer'];
88
/** Reference to drawer panel element */
89
panelRef?: React.Ref<HTMLDivElement>;
90
/** Custom class names for different parts */
91
classNames?: DrawerClassNames;
92
/** Custom styles for different parts */
93
styles?: DrawerStyles;
94
}
95
```
96
97
### Placement and Positioning
98
99
Control where the drawer appears and how it animates into view.
100
101
```typescript { .api }
102
type Placement = 'left' | 'top' | 'right' | 'bottom';
103
104
interface DrawerPopupProps {
105
/** Drawer placement position (default: 'right') */
106
placement?: Placement;
107
/** Drawer width for left/right placement or height for top/bottom */
108
width?: number | string;
109
/** Drawer height for top/bottom placement */
110
height?: number | string;
111
/** Custom motion configuration or function returning motion config */
112
motion?: CSSMotionProps | ((placement: Placement) => CSSMotionProps);
113
/** z-index for drawer stacking */
114
zIndex?: number;
115
}
116
```
117
118
**Usage Example:**
119
120
```typescript
121
// Left sidebar drawer
122
<Drawer placement="left" width={250} open={leftOpen}>
123
<Navigation />
124
</Drawer>
125
126
// Top notification drawer
127
<Drawer placement="top" height={100} open={notificationOpen}>
128
<Notifications />
129
</Drawer>
130
131
// Custom animation
132
<Drawer
133
placement="right"
134
motion={(placement) => ({
135
motionName: `slide-${placement}`,
136
duration: 300
137
})}
138
open={customOpen}
139
>
140
<Content />
141
</Drawer>
142
```
143
144
### Mask and Backdrop Control
145
146
Configure the backdrop overlay and its behavior.
147
148
```typescript { .api }
149
interface DrawerPopupProps {
150
/** Whether to show backdrop mask (default: true) */
151
mask?: boolean;
152
/** Whether clicking mask closes drawer (default: true) */
153
maskClosable?: boolean;
154
/** Custom mask CSS class name */
155
maskClassName?: string;
156
/** Custom mask inline styles */
157
maskStyle?: React.CSSProperties;
158
/** Custom mask animation configuration */
159
maskMotion?: CSSMotionProps;
160
}
161
```
162
163
**Usage Example:**
164
165
```typescript
166
// Drawer without backdrop
167
<Drawer mask={false} open={open}>
168
<Content />
169
</Drawer>
170
171
// Drawer with custom mask styling
172
<Drawer
173
maskStyle={{ backgroundColor: 'rgba(0, 0, 0, 0.8)' }}
174
maskClassName="custom-mask"
175
open={open}
176
>
177
<Content />
178
</Drawer>
179
```
180
181
### Nested Drawer Management
182
183
Support for multiple drawers with push/pull behavior.
184
185
```typescript { .api }
186
interface PushConfig {
187
/** Push distance for nested drawers */
188
distance?: number | string;
189
}
190
191
interface DrawerPopupProps {
192
/** Push configuration for nested drawers (default: true with 180px distance) */
193
push?: boolean | PushConfig;
194
}
195
196
interface DrawerContextProps {
197
/** Current push distance */
198
pushDistance?: number | string;
199
/** Function to push parent content */
200
push: VoidFunction;
201
/** Function to pull parent content back */
202
pull: VoidFunction;
203
}
204
```
205
206
**Usage Example:**
207
208
```typescript
209
// Nested drawers with custom push distance
210
<Drawer open={level1Open} push={{ distance: 200 }}>
211
<div>
212
<h2>Level 1 Drawer</h2>
213
<button onClick={() => setLevel2Open(true)}>Open Level 2</button>
214
<Drawer open={level2Open} push={{ distance: 150 }}>
215
<h3>Level 2 Drawer</h3>
216
</Drawer>
217
</div>
218
</Drawer>
219
220
// Disable push behavior
221
<Drawer push={false} open={open}>
222
<Content />
223
</Drawer>
224
```
225
226
### Event Handling
227
228
Comprehensive event handling for user interactions.
229
230
```typescript { .api }
231
interface DrawerPanelEvents {
232
/** Mouse enter event on drawer panel */
233
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
234
/** Mouse over event on drawer panel */
235
onMouseOver?: React.MouseEventHandler<HTMLDivElement>;
236
/** Mouse leave event on drawer panel */
237
onMouseLeave?: React.MouseEventHandler<HTMLDivElement>;
238
/** Click event on drawer panel */
239
onClick?: React.MouseEventHandler<HTMLDivElement>;
240
/** Key down event on drawer panel */
241
onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
242
/** Key up event on drawer panel */
243
onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;
244
}
245
246
interface DrawerProps {
247
/** Called after drawer open/close animation completes */
248
afterOpenChange?: (open: boolean) => void;
249
/** Called when drawer should be closed (ESC key, mask click, etc.) */
250
onClose?: (e: React.MouseEvent | React.KeyboardEvent) => void;
251
}
252
```
253
254
### Focus and Keyboard Management
255
256
Built-in accessibility features for keyboard navigation and focus management.
257
258
```typescript { .api }
259
interface DrawerPopupProps {
260
/** Whether to auto-focus drawer when opened (default: true) */
261
autoFocus?: boolean;
262
/** Whether to enable keyboard support like ESC to close (default: true) */
263
keyboard?: boolean;
264
}
265
```
266
267
**Usage Example:**
268
269
```typescript
270
// Drawer with custom keyboard handling
271
<Drawer
272
keyboard={false} // Disable built-in ESC handling
273
autoFocus={false} // Don't auto-focus
274
onKeyDown={(e) => {
275
if (e.key === 'Escape' && customCondition) {
276
handleCustomClose();
277
}
278
}}
279
open={open}
280
>
281
<Content />
282
</Drawer>
283
```
284
285
### Accessibility Support
286
287
Full ARIA attributes support for screen readers and assistive technologies.
288
289
```typescript { .api }
290
type DrawerPanelAccessibility = Pick<
291
React.DialogHTMLAttributes<HTMLDivElement>,
292
keyof React.AriaAttributes
293
>;
294
295
interface DrawerProps extends DrawerPanelAccessibility {
296
// All ARIA attributes are supported
297
'aria-labelledby'?: string;
298
'aria-describedby'?: string;
299
'aria-label'?: string;
300
// ... all other ARIA attributes
301
}
302
```
303
304
**Usage Example:**
305
306
```typescript
307
<Drawer
308
open={open}
309
aria-labelledby="drawer-title"
310
aria-describedby="drawer-description"
311
>
312
<h2 id="drawer-title">Settings</h2>
313
<p id="drawer-description">Configure your application settings</p>
314
<SettingsForm />
315
</Drawer>
316
```
317
318
### Advanced Styling
319
320
Comprehensive styling customization with CSS classes and inline styles.
321
322
```typescript { .api }
323
interface DrawerClassNames {
324
/** Class name for mask overlay */
325
mask?: string;
326
/** Class name for content wrapper */
327
wrapper?: string;
328
/** Class name for content section */
329
section?: string;
330
}
331
332
interface DrawerStyles {
333
/** Styles for mask overlay */
334
mask?: React.CSSProperties;
335
/** Styles for content wrapper */
336
wrapper?: React.CSSProperties;
337
/** Styles for content section */
338
section?: React.CSSProperties;
339
}
340
341
interface DrawerPopupProps {
342
/** Root container CSS class */
343
rootClassName?: string;
344
/** Root container inline styles */
345
rootStyle?: React.CSSProperties;
346
/** Drawer content CSS class */
347
className?: string;
348
/** Drawer content inline styles */
349
style?: React.CSSProperties;
350
/** Element ID for the drawer */
351
id?: string;
352
/** Custom render function for drawer content */
353
drawerRender?: (node: React.ReactNode) => React.ReactNode;
354
}
355
```
356
357
**Usage Example:**
358
359
```typescript
360
<Drawer
361
classNames={{
362
mask: 'custom-mask-class',
363
wrapper: 'custom-wrapper-class',
364
section: 'custom-section-class'
365
}}
366
styles={{
367
mask: { backgroundColor: 'rgba(0, 0, 0, 0.5)' },
368
wrapper: { boxShadow: '0 4px 20px rgba(0, 0, 0, 0.15)' },
369
section: { padding: '24px' }
370
}}
371
rootClassName="drawer-container"
372
className="drawer-content"
373
drawerRender={(content) => (
374
<div className="custom-drawer-wrapper">
375
{content}
376
</div>
377
)}
378
open={open}
379
>
380
<Content />
381
</Drawer>
382
```
383
384
### Rendering Control
385
386
Control when and how the drawer is rendered in the DOM.
387
388
```typescript { .api }
389
interface DrawerPopupProps {
390
/** Force render drawer even when closed */
391
forceRender?: boolean;
392
/** Whether drawer is rendered inline (no portal) */
393
inline?: boolean;
394
}
395
396
interface DrawerProps {
397
/** Whether to destroy drawer content when closed */
398
destroyOnClose?: boolean;
399
/** Portal container for drawer rendering */
400
getContainer?: PortalProps['getContainer'];
401
}
402
```
403
404
**Usage Example:**
405
406
```typescript
407
// Always keep drawer in DOM
408
<Drawer forceRender open={open}>
409
<ExpensiveComponent />
410
</Drawer>
411
412
// Render inline (no portal)
413
<div className="drawer-container">
414
<Drawer getContainer={false} open={open}>
415
<Content />
416
</Drawer>
417
</div>
418
419
// Custom container
420
<Drawer getContainer={() => document.getElementById('drawer-root')}>
421
<Content />
422
</Drawer>
423
```
424
425
## Default Values
426
427
The Drawer component comes with sensible defaults:
428
429
- `prefixCls`: `'rc-drawer'`
430
- `placement`: `'right'`
431
- `autoFocus`: `true`
432
- `keyboard`: `true`
433
- `width`: `378`
434
- `mask`: `true`
435
- `maskClosable`: `true`
436
- `pushDistance`: `180` (for nested drawers)
437
438
## Error Handling
439
440
The component includes built-in validation and warnings:
441
442
- Warns about deprecated props in development mode
443
- Validates proper SSR usage (drawer should not be open during SSR)
444
- Validates width/height value types
445
446
## TypeScript Support
447
448
RC-Drawer is built with TypeScript and provides complete type definitions:
449
450
```typescript { .api }
451
// Main component export
452
export default Drawer;
453
454
// Type exports
455
export type { DrawerProps };
456
```
457
458
**Note**: Internal types like `Placement`, `DrawerClassNames`, `DrawerStyles`, and `PushConfig` are part of the `DrawerProps` interface but not directly exported as standalone types. Access them through the main `DrawerProps` type or define them inline in your TypeScript code when needed.