0
# Draggable Component
1
2
The Draggable component is a stateful React component that wraps an existing element and makes it draggable using CSS transforms. It manages its own position state and provides extensive configuration options for controlling drag behavior, boundaries, and styling.
3
4
## Capabilities
5
6
### Core Component
7
8
The main Draggable component that handles position management internally.
9
10
```typescript { .api }
11
/**
12
* A React component that makes its single child element draggable
13
* @param props - Draggable configuration properties
14
*/
15
function Draggable(props: DraggableProps): React.ReactElement;
16
17
interface DraggableProps extends DraggableCoreProps {
18
// Movement constraints
19
axis?: 'both' | 'x' | 'y' | 'none';
20
bounds?: DraggableBounds | string | false;
21
22
// Position management
23
defaultPosition?: ControlPosition;
24
position?: ControlPosition;
25
positionOffset?: PositionOffsetControlPosition;
26
27
// Styling classes
28
defaultClassName?: string;
29
defaultClassNameDragging?: string;
30
defaultClassNameDragged?: string;
31
}
32
```
33
34
**Usage Examples:**
35
36
```javascript
37
import React from 'react';
38
import Draggable from 'react-draggable';
39
40
// Basic draggable element
41
function BasicDraggable() {
42
return (
43
<Draggable>
44
<div className="box">Basic draggable</div>
45
</Draggable>
46
);
47
}
48
49
// Draggable with axis constraint
50
function AxisConstrainedDraggable() {
51
return (
52
<Draggable axis="x">
53
<div className="slider">Horizontal only</div>
54
</Draggable>
55
);
56
}
57
58
// Controlled draggable
59
function ControlledDraggable() {
60
const [position, setPosition] = React.useState({ x: 0, y: 0 });
61
62
const handleDrag = (e, data) => {
63
setPosition({ x: data.x, y: data.y });
64
};
65
66
return (
67
<Draggable position={position} onDrag={handleDrag}>
68
<div>Position: {position.x}, {position.y}</div>
69
</Draggable>
70
);
71
}
72
```
73
74
### Position Management
75
76
Control element positioning with various options for initial position, controlled positioning, and position offsets.
77
78
```typescript { .api }
79
/**
80
* Initial position for uncontrolled draggable elements
81
*/
82
defaultPosition?: ControlPosition;
83
84
/**
85
* Controlled position - makes the component controlled
86
* When provided, component position is externally managed
87
*/
88
position?: ControlPosition;
89
90
/**
91
* Position offset from the element's natural position
92
* Supports pixel values or percentage strings
93
*/
94
positionOffset?: PositionOffsetControlPosition;
95
96
interface ControlPosition {
97
x: number;
98
y: number;
99
}
100
101
interface PositionOffsetControlPosition {
102
x: number | string;
103
y: number | string;
104
}
105
```
106
107
**Usage Examples:**
108
109
```javascript
110
import React, { useState } from 'react';
111
import Draggable from 'react-draggable';
112
113
// Uncontrolled with initial position
114
<Draggable defaultPosition={{ x: 100, y: 50 }}>
115
<div>Starts at (100, 50)</div>
116
</Draggable>
117
118
// Controlled positioning
119
function ControlledExample() {
120
const [pos, setPos] = useState({ x: 0, y: 0 });
121
122
return (
123
<Draggable
124
position={pos}
125
onDrag={(e, data) => setPos({ x: data.x, y: data.y })}
126
>
127
<div>Controlled position</div>
128
</Draggable>
129
);
130
}
131
132
// Position offset with percentages
133
<Draggable positionOffset={{ x: '50%', y: 20 }}>
134
<div>Offset from natural position</div>
135
</Draggable>
136
```
137
138
### Movement Constraints
139
140
Control which axes the element can move along and define movement boundaries.
141
142
```typescript { .api }
143
/**
144
* Constrains movement to specific axes
145
* 'both' - move freely (default)
146
* 'x' - horizontal movement only
147
* 'y' - vertical movement only
148
* 'none' - no movement (useful for touch scrolling)
149
*/
150
axis?: 'both' | 'x' | 'y' | 'none';
151
152
/**
153
* Boundaries for draggable movement
154
* Object - pixel boundaries: { left?: number, top?: number, right?: number, bottom?: number }
155
* 'parent' - restricted to offsetParent element
156
* CSS selector string - restricted to first matching element
157
* false - no boundaries (default)
158
*/
159
bounds?: DraggableBounds | string | false;
160
161
interface DraggableBounds {
162
left?: number;
163
right?: number;
164
top?: number;
165
bottom?: number;
166
}
167
```
168
169
**Usage Examples:**
170
171
```javascript
172
// Vertical slider
173
<Draggable axis="y" bounds={{ top: 0, bottom: 300 }}>
174
<div className="vertical-slider">Vertical only</div>
175
</Draggable>
176
177
// Bounded to parent element
178
<div className="container">
179
<Draggable bounds="parent">
180
<div>Can't leave parent</div>
181
</Draggable>
182
</div>
183
184
// Custom boundary selector
185
<Draggable bounds=".drag-area">
186
<div>Bounded to .drag-area element</div>
187
</Draggable>
188
189
// Pixel boundaries
190
<Draggable bounds={{ left: 0, top: 0, right: 500, bottom: 300 }}>
191
<div>Bounded to specific area</div>
192
</Draggable>
193
```
194
195
### Grid Snapping and Scaling
196
197
Snap movement to grid positions and scale drag calculations for zoomed interfaces.
198
199
```typescript { .api }
200
/**
201
* Snap dragging to a grid
202
* [x, y] - grid cell size in pixels for each axis
203
*/
204
grid?: [number, number];
205
206
/**
207
* Scale factor for drag distance calculations
208
* Useful when the draggable is inside a scaled/zoomed container
209
*/
210
scale?: number;
211
```
212
213
**Usage Examples:**
214
215
```javascript
216
// Snap to 20px grid
217
<Draggable grid={[20, 20]}>
218
<div>Snaps to grid</div>
219
</Draggable>
220
221
// Scale for zoomed interface (50% zoom)
222
<Draggable scale={0.5}>
223
<div>Scaled drag calculations</div>
224
</Draggable>
225
```
226
227
### Interaction Controls
228
229
Configure drag handles, cancel zones, and interaction behavior.
230
231
```typescript { .api }
232
/**
233
* CSS selector for drag handle
234
* Only elements matching this selector can initiate drag
235
*/
236
handle?: string;
237
238
/**
239
* CSS selector for cancel zones
240
* Elements matching this selector will not trigger drag
241
*/
242
cancel?: string;
243
244
/**
245
* Disable all dragging functionality
246
*/
247
disabled?: boolean;
248
249
/**
250
* Allow dragging with any mouse button (not just left-click)
251
*/
252
allowAnyClick?: boolean;
253
254
/**
255
* Allow normal scrolling on mobile touch devices
256
* Prevents drag on scroll gestures
257
*/
258
allowMobileScroll?: boolean;
259
```
260
261
**Usage Examples:**
262
263
```javascript
264
// Drag handle - only the .handle element starts drag
265
<Draggable handle=".handle">
266
<div>
267
<div className="handle">Drag me</div>
268
<div>Content area - not draggable</div>
269
</div>
270
</Draggable>
271
272
// Cancel zones - .no-drag elements prevent drag
273
<Draggable cancel=".no-drag">
274
<div>
275
<button className="no-drag">Button (not draggable)</button>
276
<div>Draggable area</div>
277
</div>
278
</Draggable>
279
280
// Mobile-friendly with scroll
281
<Draggable allowMobileScroll>
282
<div>Touch and drag, or scroll normally</div>
283
</Draggable>
284
```
285
286
### Event Handlers
287
288
Handle drag lifecycle events with detailed position and delta information.
289
290
```typescript { .api }
291
/**
292
* Called when dragging starts
293
* Return false to cancel the drag
294
*/
295
onStart?: DraggableEventHandler;
296
297
/**
298
* Called continuously during drag
299
* Return false to stop the drag
300
*/
301
onDrag?: DraggableEventHandler;
302
303
/**
304
* Called when dragging stops
305
*/
306
onStop?: DraggableEventHandler;
307
308
/**
309
* Called on mouse down events (before drag start)
310
*/
311
onMouseDown?: (e: MouseEvent) => void;
312
313
type DraggableEventHandler = (
314
e: DraggableEvent,
315
data: DraggableData
316
) => void | false;
317
318
interface DraggableData {
319
node: HTMLElement; // The dragged DOM element
320
x: number; // Current x position
321
y: number; // Current y position
322
deltaX: number; // Change in x since last event
323
deltaY: number; // Change in y since last event
324
lastX: number; // Previous x position
325
lastY: number; // Previous y position
326
}
327
```
328
329
**Usage Examples:**
330
331
```javascript
332
function EventHandlingDraggable() {
333
const handleStart = (e, data) => {
334
console.log('Drag started at:', data.x, data.y);
335
// Return false to cancel drag
336
if (data.x < 0) return false;
337
};
338
339
const handleDrag = (e, data) => {
340
console.log('Dragging:', {
341
position: [data.x, data.y],
342
delta: [data.deltaX, data.deltaY]
343
});
344
};
345
346
const handleStop = (e, data) => {
347
console.log('Drag stopped at:', data.x, data.y);
348
};
349
350
return (
351
<Draggable
352
onStart={handleStart}
353
onDrag={handleDrag}
354
onStop={handleStop}
355
>
356
<div>Event handling draggable</div>
357
</Draggable>
358
);
359
}
360
```
361
362
### Styling Classes
363
364
Customize CSS classes applied during different drag states.
365
366
```typescript { .api }
367
/**
368
* Base CSS class applied to the draggable element
369
* Default: 'react-draggable'
370
*/
371
defaultClassName?: string;
372
373
/**
374
* CSS class applied while dragging
375
* Default: 'react-draggable-dragging'
376
*/
377
defaultClassNameDragging?: string;
378
379
/**
380
* CSS class applied after element has been dragged
381
* Default: 'react-draggable-dragged'
382
*/
383
defaultClassNameDragged?: string;
384
```
385
386
**Usage Examples:**
387
388
```javascript
389
<Draggable
390
defaultClassName="my-draggable"
391
defaultClassNameDragging="my-draggable--dragging"
392
defaultClassNameDragged="my-draggable--dragged"
393
>
394
<div>Custom styled draggable</div>
395
</Draggable>
396
```
397
398
### Advanced Options
399
400
Advanced configuration for specific use cases and React compatibility.
401
402
```typescript { .api }
403
/**
404
* Automatically add user-select: none styles during drag
405
* Prevents text selection while dragging
406
*/
407
enableUserSelectHack?: boolean;
408
409
/**
410
* Custom offset parent for position calculations
411
* Used for calculating relative positions
412
*/
413
offsetParent?: HTMLElement;
414
415
/**
416
* React ref for the draggable element
417
* Recommended for React Strict Mode compatibility (avoids findDOMNode)
418
*/
419
nodeRef?: React.RefObject<HTMLElement>;
420
```
421
422
**Usage Examples:**
423
424
```javascript
425
import React, { useRef } from 'react';
426
import Draggable from 'react-draggable';
427
428
function AdvancedDraggable() {
429
const nodeRef = useRef(null);
430
431
return (
432
<Draggable
433
nodeRef={nodeRef}
434
enableUserSelectHack={false} // Allow text selection during drag
435
>
436
<div ref={nodeRef}>
437
Advanced draggable with ref
438
</div>
439
</Draggable>
440
);
441
}
442
```