0
# Configuration & Types
1
2
Type definitions and interfaces for configuring drawer behavior. This section covers all the available options for customizing drawer behavior, animations, and interactions.
3
4
## Capabilities
5
6
### DialogProps Interface
7
8
Main configuration interface for the Root component that controls all aspects of drawer behavior.
9
10
```typescript { .api }
11
/**
12
* Main props interface for Root component
13
* Union of WithFadeFromProps or WithoutFadeFromProps
14
*/
15
type DialogProps = (WithFadeFromProps | WithoutFadeFromProps) & BaseDialogProps;
16
17
interface BaseDialogProps {
18
/** Controlled open state */
19
open?: boolean;
20
/** Callback fired when open state changes */
21
onOpenChange?: (open: boolean) => void;
22
/** Default open state for uncontrolled usage */
23
defaultOpen?: boolean;
24
/** Child components */
25
children?: React.ReactNode;
26
/** Controlled active snap point */
27
activeSnapPoint?: number | string | null;
28
/** Callback to set active snap point */
29
setActiveSnapPoint?: (snapPoint: number | string | null) => void;
30
/** Threshold for closing (default: 0.25) */
31
closeThreshold?: number;
32
/** Prevent body style changes */
33
noBodyStyles?: boolean;
34
/** Enable background scaling effect */
35
shouldScaleBackground?: boolean;
36
/** Change background color when scaling */
37
setBackgroundColorOnScale?: boolean;
38
/** Duration for scroll lock in ms (default: 100) */
39
scrollLockTimeout?: number;
40
/** Fixed positioning behavior */
41
fixed?: boolean;
42
/** Restrict dragging to handle only */
43
handleOnly?: boolean;
44
/** Allow dismissal via gestures (default: true) */
45
dismissible?: boolean;
46
/** Drag event handler */
47
onDrag?: (event: React.PointerEvent<HTMLDivElement>, percentageDragged: number) => void;
48
/** Release event handler */
49
onRelease?: (event: React.PointerEvent<HTMLDivElement>, open: boolean) => void;
50
/** Modal behavior (default: true) */
51
modal?: boolean;
52
/** Nested drawer support */
53
nested?: boolean;
54
/** Close callback */
55
onClose?: () => void;
56
/** Drawer direction (default: 'bottom') */
57
direction?: DrawerDirection;
58
/** Disable scroll prevention (default: true) */
59
disablePreventScroll?: boolean;
60
/** Reposition inputs on keyboard */
61
repositionInputs?: boolean;
62
/** Disable velocity-based snapping */
63
snapToSequentialPoint?: boolean;
64
/** Portal container */
65
container?: HTMLElement | null;
66
/** Animation end callback */
67
onAnimationEnd?: (open: boolean) => void;
68
/** Prevent scroll restoration */
69
preventScrollRestoration?: boolean;
70
/** Auto focus behavior */
71
autoFocus?: boolean;
72
}
73
```
74
75
### Snap Points Configuration
76
77
Snap points allow drawers to "snap" to specific positions, creating multi-height drawer experiences.
78
79
```typescript { .api }
80
/**
81
* Props for drawers with fade configuration
82
*/
83
interface WithFadeFromProps {
84
/** Array of snap points - numbers 0-100 for % or px values like "300px" */
85
snapPoints: (number | string)[];
86
/** Index from which overlay fade should be applied */
87
fadeFromIndex: number;
88
}
89
90
/**
91
* Props for drawers without fade configuration
92
*/
93
interface WithoutFadeFromProps {
94
/** Optional array of snap points */
95
snapPoints?: (number | string)[];
96
/** Not allowed when snapPoints are optional */
97
fadeFromIndex?: never;
98
}
99
```
100
101
**Usage Examples:**
102
103
```typescript
104
// Drawer with snap points and fade
105
<Drawer.Root
106
snapPoints={[0.2, 0.5, 0.8]}
107
fadeFromIndex={1} // Fade starts from 50% height
108
>
109
{/* drawer content */}
110
</Drawer.Root>
111
112
// Drawer with pixel-based snap points
113
<Drawer.Root
114
snapPoints={["100px", "300px", "500px"]}
115
fadeFromIndex={0}
116
>
117
{/* drawer content */}
118
</Drawer.Root>
119
120
// Drawer without snap points
121
<Drawer.Root>
122
{/* drawer content */}
123
</Drawer.Root>
124
```
125
126
### Direction and Positioning
127
128
Control drawer direction and positioning behavior.
129
130
```typescript { .api }
131
/**
132
* Valid drawer directions
133
*/
134
type DrawerDirection = 'top' | 'bottom' | 'left' | 'right';
135
136
/**
137
* Snap point configuration interface
138
*/
139
interface SnapPoint {
140
/** Fraction of screen height/width (0-1) */
141
fraction: number;
142
/** Absolute height/width in pixels */
143
height: number;
144
}
145
```
146
147
**Usage Examples:**
148
149
```typescript
150
// Bottom drawer (default)
151
<Drawer.Root direction="bottom">
152
{/* content */}
153
</Drawer.Root>
154
155
// Side drawer
156
<Drawer.Root direction="right">
157
{/* content */}
158
</Drawer.Root>
159
160
// Top drawer
161
<Drawer.Root direction="top">
162
{/* content */}
163
</Drawer.Root>
164
```
165
166
### Event Handlers
167
168
Event handling configuration for custom behavior during drawer interactions.
169
170
```typescript { .api }
171
/**
172
* Drag event handler type
173
*/
174
type DragHandler = (event: React.PointerEvent<HTMLDivElement>, percentageDragged: number) => void;
175
176
/**
177
* Release event handler type
178
*/
179
type ReleaseHandler = (event: React.PointerEvent<HTMLDivElement>, open: boolean) => void;
180
181
/**
182
* Animation end handler type
183
*/
184
type AnimationEndHandler = (open: boolean) => void;
185
```
186
187
**Usage Examples:**
188
189
```typescript
190
function CustomDrawer() {
191
const handleDrag = (event: React.PointerEvent<HTMLDivElement>, percentage: number) => {
192
console.log(`Dragged to ${percentage}%`);
193
// Custom drag behavior
194
};
195
196
const handleRelease = (event: React.PointerEvent<HTMLDivElement>, open: boolean) => {
197
console.log(`Released, drawer is ${open ? 'open' : 'closed'}`);
198
// Custom release behavior
199
};
200
201
const handleAnimationEnd = (open: boolean) => {
202
console.log(`Animation ended, drawer is ${open ? 'open' : 'closed'}`);
203
// Post-animation logic
204
};
205
206
return (
207
<Drawer.Root
208
onDrag={handleDrag}
209
onRelease={handleRelease}
210
onAnimationEnd={handleAnimationEnd}
211
>
212
{/* drawer content */}
213
</Drawer.Root>
214
);
215
}
216
```
217
218
### Individual Type Exports
219
220
These types are exported individually for direct use in TypeScript projects.
221
222
```typescript { .api }
223
/**
224
* Props interface for drawers with fade configuration
225
*/
226
interface WithFadeFromProps {
227
/** Array of snap points - numbers 0-100 for % or px values like "300px" */
228
snapPoints: (number | string)[];
229
/** Index from which overlay fade should be applied */
230
fadeFromIndex: number;
231
}
232
233
/**
234
* Props interface for drawers without fade configuration
235
*/
236
interface WithoutFadeFromProps {
237
/** Optional array of snap points */
238
snapPoints?: (number | string)[];
239
/** Not allowed when snapPoints are optional */
240
fadeFromIndex?: never;
241
}
242
243
/**
244
* Props type for Content component - exported individually
245
*/
246
type ContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>;
247
248
/**
249
* Props type for Handle component - exported individually
250
*/
251
interface HandleProps extends React.ComponentPropsWithoutRef<'div'> {
252
/** Prevent snap point cycling when dragging the handle */
253
preventCycle?: boolean;
254
}
255
```
256
257
### Component-Specific Types
258
259
Additional type definitions for individual components.
260
261
```typescript { .api }
262
/**
263
* Props type for Portal component (internal)
264
*/
265
type PortalProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Portal> & {
266
/** Override container for portal rendering */
267
container?: HTMLElement;
268
}
269
```
270
271
### Advanced Configuration
272
273
Advanced configuration options for fine-tuning drawer behavior.
274
275
```typescript { .api }
276
/**
277
* Advanced configuration options
278
*/
279
interface AdvancedConfig {
280
/** Threshold for closing drawer (0-1, default: 0.25) */
281
closeThreshold?: number;
282
/** Timeout for scroll lock in milliseconds (default: 100) */
283
scrollLockTimeout?: number;
284
/** Prevent default body style changes */
285
noBodyStyles?: boolean;
286
/** Scale background content when drawer opens */
287
shouldScaleBackground?: boolean;
288
/** Change background color during scaling */
289
setBackgroundColorOnScale?: boolean;
290
/** Use fixed positioning */
291
fixed?: boolean;
292
/** Only allow dragging via handle */
293
handleOnly?: boolean;
294
/** Disable gesture-based dismissal */
295
dismissible?: boolean;
296
/** Disable scroll prevention (default: true) */
297
disablePreventScroll?: boolean;
298
/** Reposition inputs when keyboard appears */
299
repositionInputs?: boolean;
300
/** Disable velocity-based snap point selection */
301
snapToSequentialPoint?: boolean;
302
/** Prevent scroll position restoration */
303
preventScrollRestoration?: boolean;
304
/** Control auto-focus behavior */
305
autoFocus?: boolean;
306
}
307
```
308
309
**Usage Examples:**
310
311
```typescript
312
// Fine-tuned drawer configuration
313
<Drawer.Root
314
closeThreshold={0.4} // Require 40% drag to close
315
scrollLockTimeout={1000} // 1 second scroll lock
316
shouldScaleBackground={true}
317
setBackgroundColorOnScale={true}
318
handleOnly={true} // Only draggable via handle
319
repositionInputs={true} // Handle mobile keyboards
320
snapToSequentialPoint={true} // Disable velocity snapping
321
>
322
{/* drawer content */}
323
</Drawer.Root>
324
325
// Mobile-optimized drawer
326
<Drawer.Root
327
fixed={true}
328
repositionInputs={true}
329
disablePreventScroll={false}
330
direction="bottom"
331
>
332
{/* mobile-friendly content */}
333
</Drawer.Root>
334
```
335
336
### Context and Hooks
337
338
Advanced context and hook types for custom drawer implementations.
339
340
```typescript { .api }
341
/**
342
* Hook to access drawer context from within drawer components
343
* @returns DrawerContextValue object with drawer state and methods
344
* @throws Error if used outside of Drawer.Root
345
*/
346
function useDrawerContext(): DrawerContextValue;
347
348
/**
349
* Context value interface containing all drawer state and methods
350
*/
351
interface DrawerContextValue {
352
/** Ref to the drawer content element */
353
drawerRef: React.RefObject<HTMLDivElement>;
354
/** Ref to the overlay element */
355
overlayRef: React.RefObject<HTMLDivElement>;
356
/** Pointer press handler */
357
onPress: (event: React.PointerEvent<HTMLDivElement>) => void;
358
/** Pointer release handler */
359
onRelease: (event: React.PointerEvent<HTMLDivElement> | null) => void;
360
/** Drag handler */
361
onDrag: (event: React.PointerEvent<HTMLDivElement>) => void;
362
/** Nested drawer drag handler */
363
onNestedDrag: (event: React.PointerEvent<HTMLDivElement>, percentageDragged: number) => void;
364
/** Nested drawer open change handler */
365
onNestedOpenChange: (open: boolean) => void;
366
/** Nested drawer release handler */
367
onNestedRelease: (event: React.PointerEvent<HTMLDivElement>, open: boolean) => void;
368
/** Whether drawer can be dismissed */
369
dismissible: boolean;
370
/** Current open state */
371
isOpen: boolean;
372
/** Current dragging state */
373
isDragging: boolean;
374
/** Keyboard visibility ref */
375
keyboardIsOpen: React.MutableRefObject<boolean>;
376
/** Computed snap point offsets */
377
snapPointsOffset: number[] | null;
378
/** Configured snap points */
379
snapPoints?: (number | string)[] | null;
380
/** Current active snap point index */
381
activeSnapPointIndex?: number | null;
382
/** Modal behavior setting */
383
modal: boolean;
384
/** Whether overlay should fade */
385
shouldFade: boolean;
386
/** Current active snap point */
387
activeSnapPoint?: number | string | null;
388
/** Function to set active snap point */
389
setActiveSnapPoint: (snapPoint: number | string | null) => void;
390
/** Function to close drawer */
391
closeDrawer: () => void;
392
/** Open prop from parent */
393
openProp?: boolean;
394
/** Open change callback from parent */
395
onOpenChange?: (open: boolean) => void;
396
/** Drawer direction */
397
direction: DrawerDirection;
398
/** Whether to scale background */
399
shouldScaleBackground: boolean;
400
/** Whether to change background color on scale */
401
setBackgroundColorOnScale: boolean;
402
/** Whether to apply body styles */
403
noBodyStyles: boolean;
404
/** Whether only handle can drag */
405
handleOnly?: boolean;
406
/** Portal container */
407
container?: HTMLElement | null;
408
/** Auto focus setting */
409
autoFocus?: boolean;
410
/** Animation state ref */
411
shouldAnimate?: React.MutableRefObject<boolean>;
412
}
413
```
414
415
**Usage Examples:**
416
417
```typescript
418
import { useDrawerContext } from "vaul";
419
420
// Custom component that uses drawer context
421
function CustomDrawerComponent() {
422
const { isOpen, closeDrawer, isDragging } = useDrawerContext();
423
424
return (
425
<div>
426
<p>Drawer is {isOpen ? 'open' : 'closed'}</p>
427
<p>Currently {isDragging ? 'dragging' : 'not dragging'}</p>
428
<button onClick={closeDrawer}>Close Drawer</button>
429
</div>
430
);
431
}
432
433
// Use within drawer content
434
<Drawer.Root>
435
<Drawer.Trigger>Open</Drawer.Trigger>
436
<Drawer.Portal>
437
<Drawer.Content>
438
<CustomDrawerComponent />
439
</Drawer.Content>
440
</Drawer.Portal>
441
</Drawer.Root>
442
```
443
444
### State Management Types
445
446
Types for controlled and uncontrolled state management.
447
448
```typescript { .api }
449
/**
450
* Controlled state configuration
451
*/
452
interface ControlledState {
453
/** Current open state */
454
open: boolean;
455
/** State change handler */
456
onOpenChange: (open: boolean) => void;
457
/** Current active snap point */
458
activeSnapPoint?: number | string | null;
459
/** Active snap point change handler */
460
setActiveSnapPoint?: (snapPoint: number | string | null) => void;
461
}
462
463
/**
464
* Uncontrolled state configuration
465
*/
466
interface UncontrolledState {
467
/** Default open state */
468
defaultOpen?: boolean;
469
/** Close callback for uncontrolled usage */
470
onClose?: () => void;
471
}
472
```
473
474
**Usage Examples:**
475
476
```typescript
477
// Controlled drawer
478
function ControlledDrawer() {
479
const [open, setOpen] = useState(false);
480
const [activeSnap, setActiveSnap] = useState<number | null>(null);
481
482
return (
483
<Drawer.Root
484
open={open}
485
onOpenChange={setOpen}
486
activeSnapPoint={activeSnap}
487
setActiveSnapPoint={setActiveSnap}
488
snapPoints={[0.3, 0.6, 0.9]}
489
>
490
{/* drawer content */}
491
</Drawer.Root>
492
);
493
}
494
495
// Uncontrolled drawer
496
function UncontrolledDrawer() {
497
return (
498
<Drawer.Root
499
defaultOpen={false}
500
onClose={() => console.log('Drawer closed')}
501
>
502
{/* drawer content */}
503
</Drawer.Root>
504
);
505
}
506
```
507
508
### Utility Types
509
510
Additional utility types used internally but may be useful for advanced usage.
511
512
```typescript { .api }
513
/**
514
* Utility type for any function
515
*/
516
type AnyFunction = (...args: any) => any;
517
518
/**
519
* Snap point configuration interface
520
*/
521
interface SnapPoint {
522
/** Fraction of screen height/width (0-1) */
523
fraction: number;
524
/** Absolute height/width in pixels */
525
height: number;
526
}
527
```