0
# Event Handling
1
2
Callback props for all drag and resize interaction phases with detailed event data. React RnD provides comprehensive event handling for all user interactions.
3
4
## Capabilities
5
6
### Drag Event Callbacks
7
8
Handle all phases of drag interactions with detailed position and delta information.
9
10
```typescript { .api }
11
/**
12
* Called when drag operation starts
13
* Can return false to cancel the drag operation
14
*/
15
onDragStart?: RndDragCallback;
16
17
/**
18
* Called continuously during drag operation
19
* Can return false to cancel the drag operation
20
*/
21
onDrag?: RndDragCallback;
22
23
/**
24
* Called when drag operation completes
25
*/
26
onDragStop?: RndDragCallback;
27
28
// RndDragCallback is imported from react-draggable as DraggableEventHandler
29
type RndDragCallback = import("react-draggable").DraggableEventHandler;
30
31
type RndDragEvent =
32
| React.MouseEvent<HTMLElement | SVGElement>
33
| React.TouchEvent<HTMLElement | SVGElement>
34
| MouseEvent
35
| TouchEvent;
36
37
interface DraggableData extends Position {
38
/** DOM element being dragged */
39
node: HTMLElement;
40
/** X coordinate in pixels */
41
x: number;
42
/** Y coordinate in pixels */
43
y: number;
44
/** Change in X since last event */
45
deltaX: number;
46
/** Change in Y since last event */
47
deltaY: number;
48
/** Previous X coordinate */
49
lastX: number;
50
/** Previous Y coordinate */
51
lastY: number;
52
}
53
```
54
55
**Usage Examples:**
56
57
```typescript
58
function DragTrackingExample() {
59
const [dragInfo, setDragInfo] = React.useState<string>('');
60
61
return (
62
<div>
63
<div>Drag Status: {dragInfo}</div>
64
<Rnd
65
default={{ x: 0, y: 0, width: 200, height: 150 }}
66
onDragStart={(e, d) => {
67
setDragInfo(`Drag started at (${d.x}, ${d.y})`);
68
console.log('Drag started:', d);
69
}}
70
onDrag={(e, d) => {
71
setDragInfo(`Dragging to (${d.x}, ${d.y}), delta: (${d.deltaX}, ${d.deltaY})`);
72
}}
73
onDragStop={(e, d) => {
74
setDragInfo(`Drag ended at (${d.x}, ${d.y})`);
75
console.log('Final position:', d.x, d.y);
76
}}
77
>
78
Drag me and watch the console
79
</Rnd>
80
</div>
81
);
82
}
83
84
// Conditional drag prevention
85
<Rnd
86
default={{ x: 0, y: 0, width: 200, height: 150 }}
87
onDragStart={(e, d) => {
88
// Prevent drag if certain condition is met
89
if (someCondition) {
90
console.log('Drag prevented');
91
return false; // Cancel drag
92
}
93
}}
94
>
95
Conditionally draggable
96
</Rnd>
97
```
98
99
### Resize Event Callbacks
100
101
Handle all phases of resize interactions with size delta and position information.
102
103
```typescript { .api }
104
/**
105
* Called when resize operation starts
106
* Can return false to cancel the resize operation
107
*/
108
onResizeStart?: RndResizeStartCallback;
109
110
/**
111
* Called continuously during resize operation
112
*/
113
onResize?: RndResizeCallback;
114
115
/**
116
* Called when resize operation completes
117
*/
118
onResizeStop?: RndResizeCallback;
119
120
type RndResizeStartCallback = (
121
e: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>,
122
dir: ResizeDirection,
123
elementRef: HTMLElement
124
) => void | boolean;
125
126
type RndResizeCallback = (
127
e: MouseEvent | TouchEvent,
128
dir: ResizeDirection,
129
elementRef: HTMLElement,
130
delta: ResizableDelta,
131
position: Position
132
) => void;
133
134
interface ResizableDelta {
135
/** Change in width since resize started */
136
width: number;
137
/** Change in height since resize started */
138
height: number;
139
}
140
141
type ResizeDirection =
142
| "top" | "right" | "bottom" | "left"
143
| "topRight" | "bottomRight" | "bottomLeft" | "topLeft";
144
```
145
146
**Usage Examples:**
147
148
```typescript
149
function ResizeTrackingExample() {
150
const [resizeInfo, setResizeInfo] = React.useState<string>('');
151
152
return (
153
<div>
154
<div>Resize Status: {resizeInfo}</div>
155
<Rnd
156
default={{ x: 0, y: 0, width: 200, height: 150 }}
157
onResizeStart={(e, dir, ref) => {
158
setResizeInfo(`Resize started from ${dir} handle`);
159
console.log('Resize started:', dir, ref.getBoundingClientRect());
160
}}
161
onResize={(e, dir, ref, delta, position) => {
162
setResizeInfo(
163
`Resizing ${dir}: ${ref.style.width} x ${ref.style.height}, ` +
164
`delta: (${delta.width}, ${delta.height}), pos: (${position.x}, ${position.y})`
165
);
166
}}
167
onResizeStop={(e, dir, ref, delta, position) => {
168
setResizeInfo(`Resize ended: ${ref.style.width} x ${ref.style.height}`);
169
console.log('Final size:', ref.style.width, ref.style.height);
170
console.log('Final position:', position);
171
}}
172
>
173
Resize me and watch the console
174
</Rnd>
175
</div>
176
);
177
}
178
179
// Conditional resize prevention
180
<Rnd
181
default={{ x: 0, y: 0, width: 200, height: 150 }}
182
onResizeStart={(e, dir, ref) => {
183
// Prevent resize from certain handles
184
if (dir === 'top' || dir === 'topLeft' || dir === 'topRight') {
185
console.log('Top resize prevented');
186
return false; // Cancel resize
187
}
188
}}
189
>
190
Only bottom/side resize allowed
191
</Rnd>
192
```
193
194
### State Management Integration
195
196
Integrate with React state management for controlled components.
197
198
```typescript
199
function ControlledRndExample() {
200
const [state, setState] = React.useState({
201
x: 0,
202
y: 0,
203
width: 200,
204
height: 150,
205
});
206
207
return (
208
<Rnd
209
size={{ width: state.width, height: state.height }}
210
position={{ x: state.x, y: state.y }}
211
onDragStop={(e, d) => {
212
setState(prev => ({
213
...prev,
214
x: d.x,
215
y: d.y,
216
}));
217
}}
218
onResizeStop={(e, direction, ref, delta, position) => {
219
setState({
220
width: ref.style.width,
221
height: ref.style.height,
222
...position,
223
});
224
}}
225
>
226
Controlled component with state
227
</Rnd>
228
);
229
}
230
```
231
232
### Mouse Event Callbacks
233
234
Handle general mouse events on the component.
235
236
```typescript { .api }
237
/**
238
* Called on mouse down events
239
* Note: This is a native MouseEvent, not React SyntheticEvent
240
*/
241
onMouseDown?: (e: MouseEvent) => void;
242
243
/**
244
* Called on mouse up events
245
* Note: This is a native MouseEvent, not React SyntheticEvent
246
*/
247
onMouseUp?: (e: MouseEvent) => void;
248
```
249
250
**Usage Examples:**
251
252
```typescript
253
<Rnd
254
default={{ x: 0, y: 0, width: 200, height: 150 }}
255
onMouseDown={(e) => {
256
console.log('Mouse down at:', e.clientX, e.clientY);
257
}}
258
onMouseUp={(e) => {
259
console.log('Mouse up at:', e.clientX, e.clientY);
260
}}
261
>
262
General mouse event handling
263
</Rnd>
264
```
265
266
## Advanced Event Patterns
267
268
### Event Coordination
269
270
Coordinate between drag and resize events for complex interactions.
271
272
```typescript
273
function CoordinatedEventsExample() {
274
const [isDragging, setIsDragging] = React.useState(false);
275
const [isResizing, setIsResizing] = React.useState(false);
276
277
return (
278
<Rnd
279
default={{ x: 0, y: 0, width: 200, height: 150 }}
280
onDragStart={() => {
281
setIsDragging(true);
282
console.log('Started dragging');
283
}}
284
onDragStop={() => {
285
setIsDragging(false);
286
console.log('Stopped dragging');
287
}}
288
onResizeStart={() => {
289
setIsResizing(true);
290
console.log('Started resizing');
291
}}
292
onResizeStop={() => {
293
setIsResizing(false);
294
console.log('Stopped resizing');
295
}}
296
style={{
297
border: isDragging ? '2px solid blue' : isResizing ? '2px solid red' : '1px solid gray',
298
}}
299
>
300
Visual feedback during interactions
301
</Rnd>
302
);
303
}
304
```
305
306
### Validation and Constraints
307
308
Use event callbacks to implement custom validation and constraints.
309
310
```typescript
311
function ValidationExample() {
312
const [errors, setErrors] = React.useState<string[]>([]);
313
314
return (
315
<div>
316
{errors.map((error, i) => (
317
<div key={i} style={{ color: 'red' }}>{error}</div>
318
))}
319
<Rnd
320
default={{ x: 0, y: 0, width: 200, height: 150 }}
321
onDrag={(e, d) => {
322
const newErrors: string[] = [];
323
if (d.x < 0) newErrors.push('Cannot move to negative X');
324
if (d.y < 0) newErrors.push('Cannot move to negative Y');
325
setErrors(newErrors);
326
}}
327
onResize={(e, dir, ref, delta, position) => {
328
const newErrors: string[] = [];
329
const width = parseInt(ref.style.width);
330
const height = parseInt(ref.style.height);
331
if (width > 500) newErrors.push('Width cannot exceed 500px');
332
if (height > 400) newErrors.push('Height cannot exceed 400px');
333
setErrors(newErrors);
334
}}
335
>
336
Validation feedback during interaction
337
</Rnd>
338
</div>
339
);
340
}
341
```
342
343
### Performance Optimization
344
345
Optimize event handling for performance-critical applications.
346
347
```typescript
348
function OptimizedEventsExample() {
349
const [position, setPosition] = React.useState({ x: 0, y: 0 });
350
const [size, setSize] = React.useState({ width: 200, height: 150 });
351
352
// Debounced state updates
353
const debouncedUpdatePosition = React.useMemo(
354
() => debounce((x: number, y: number) => setPosition({ x, y }), 100),
355
[]
356
);
357
358
return (
359
<Rnd
360
default={{ x: 0, y: 0, width: 200, height: 150 }}
361
onDrag={(e, d) => {
362
// Update immediately for smooth interaction
363
// Debounced state update for expensive operations
364
debouncedUpdatePosition(d.x, d.y);
365
}}
366
onResizeStop={(e, dir, ref, delta, pos) => {
367
// Only update state on stop for better performance
368
setSize({
369
width: parseInt(ref.style.width),
370
height: parseInt(ref.style.height)
371
});
372
setPosition(pos);
373
}}
374
>
375
Performance optimized events
376
</Rnd>
377
);
378
}
379
```