0
# Events
1
2
Rich event lifecycle with callbacks for drag start/end, list changes, and custom interactions.
3
4
## Capabilities
5
6
### Drag Lifecycle Events
7
8
Events that track the complete drag and drop lifecycle from selection to completion.
9
10
#### onChoose
11
12
Called when an element is selected for dragging.
13
14
```javascript { .api }
15
/**
16
* Called when element is chosen (selected for dragging)
17
* @param evt - Event object with oldIndex property
18
*/
19
onChoose?: (evt: SortableEvent) => void;
20
```
21
22
**Usage Examples:**
23
24
```javascript
25
Sortable.create(el, {
26
onChoose: (evt) => {
27
console.log('Item chosen at index:', evt.oldIndex);
28
evt.item.classList.add('being-dragged');
29
}
30
});
31
```
32
33
#### onUnchoose
34
35
Called when element selection is cancelled before dragging starts.
36
37
```javascript { .api }
38
/**
39
* Called when element selection is cancelled
40
* @param evt - Event object with same properties as onEnd
41
*/
42
onUnchoose?: (evt: SortableEvent) => void;
43
```
44
45
#### onStart
46
47
Called when dragging starts (after any configured delay).
48
49
```javascript { .api }
50
/**
51
* Called when dragging actually starts
52
* @param evt - Event object with oldIndex and item properties
53
*/
54
onStart?: (evt: SortableEvent) => void;
55
```
56
57
**Usage Examples:**
58
59
```javascript
60
Sortable.create(el, {
61
onStart: (evt) => {
62
console.log('Drag started:', evt.item.textContent);
63
document.body.classList.add('dragging-active');
64
}
65
});
66
```
67
68
#### onEnd
69
70
Called when dragging ends (whether successful or cancelled).
71
72
```javascript { .api }
73
/**
74
* Called when dragging ends
75
* @param evt - Event object with comprehensive drag information
76
*/
77
onEnd?: (evt: SortableEvent) => void;
78
```
79
80
**Usage Examples:**
81
82
```javascript
83
Sortable.create(el, {
84
onEnd: (evt) => {
85
document.body.classList.remove('dragging-active');
86
87
if (evt.oldIndex !== evt.newIndex) {
88
console.log(`Item moved from ${evt.oldIndex} to ${evt.newIndex}`);
89
// Save new order
90
saveOrder(evt.from);
91
}
92
}
93
});
94
```
95
96
### List Change Events
97
98
Events that fire when the list structure changes due to drag operations.
99
100
#### onAdd
101
102
Called when an element is added to the list from another list.
103
104
```javascript { .api }
105
/**
106
* Called when element is added from another list
107
* @param evt - Event object with same properties as onEnd
108
*/
109
onAdd?: (evt: SortableEvent) => void;
110
```
111
112
**Usage Examples:**
113
114
```javascript
115
Sortable.create(targetList, {
116
onAdd: (evt) => {
117
console.log('Item added from another list:', evt.item.textContent);
118
console.log('Added at index:', evt.newIndex);
119
120
// Update data model
121
addItemToList(evt.item.dataset.id, evt.newIndex);
122
123
// Animate the new item
124
evt.item.classList.add('newly-added');
125
setTimeout(() => evt.item.classList.remove('newly-added'), 300);
126
}
127
});
128
```
129
130
#### onUpdate
131
132
Called when element order changes within the same list.
133
134
```javascript { .api }
135
/**
136
* Called when list order changes within the same list
137
* @param evt - Event object with same properties as onEnd
138
*/
139
onUpdate?: (evt: SortableEvent) => void;
140
```
141
142
#### onRemove
143
144
Called when an element is removed from the list to another list.
145
146
```javascript { .api }
147
/**
148
* Called when element is removed to another list
149
* @param evt - Event object with same properties as onEnd
150
*/
151
onRemove?: (evt: SortableEvent) => void;
152
```
153
154
#### onSort
155
156
Called for any list change (add, update, or remove).
157
158
```javascript { .api }
159
/**
160
* Called for any change to the list (add/update/remove)
161
* @param evt - Event object with same properties as onEnd
162
*/
163
onSort?: (evt: SortableEvent) => void;
164
```
165
166
**Usage Examples:**
167
168
```javascript
169
Sortable.create(el, {
170
onSort: (evt) => {
171
// This fires for any list change
172
console.log('List changed:', evt.type);
173
174
// Save to localStorage
175
const order = Array.from(evt.to.children)
176
.map(item => item.dataset.id);
177
localStorage.setItem('list-order', JSON.stringify(order));
178
}
179
});
180
```
181
182
### Interaction Events
183
184
Events for handling special interactions and custom drag behavior.
185
186
#### onFilter
187
188
Called when attempting to drag a filtered (non-draggable) element.
189
190
```javascript { .api }
191
/**
192
* Called when trying to drag a filtered element
193
* @param evt - Event object with item property
194
*/
195
onFilter?: (evt: SortableEvent) => void;
196
```
197
198
**Usage Examples:**
199
200
```javascript
201
Sortable.create(el, {
202
filter: '.locked',
203
onFilter: (evt) => {
204
console.log('Cannot drag locked item:', evt.item.textContent);
205
206
// Show user feedback
207
evt.item.classList.add('shake-animation');
208
setTimeout(() => evt.item.classList.remove('shake-animation'), 500);
209
}
210
});
211
```
212
213
#### onMove
214
215
Called when an element moves during dragging, allows controlling insertion behavior.
216
217
```javascript { .api }
218
/**
219
* Called when element moves during drag, can control insertion
220
* @param evt - Event object with movement data
221
* @param originalEvent - Original DOM event
222
* @returns Control insertion: false (cancel), -1 (before), 1 (after), true/void (default)
223
*/
224
onMove?: (evt: SortableEvent, originalEvent: Event) => boolean | number | void;
225
```
226
227
**Usage Examples:**
228
229
```javascript
230
Sortable.create(el, {
231
onMove: (evt, originalEvent) => {
232
// Prevent dropping on certain elements
233
if (evt.related.classList.contains('no-drop')) {
234
return false; // Cancel the move
235
}
236
237
// Custom insertion logic
238
if (evt.related.classList.contains('insert-before')) {
239
return -1; // Force insert before
240
}
241
242
if (evt.related.classList.contains('insert-after')) {
243
return 1; // Force insert after
244
}
245
246
// Allow default behavior
247
return true;
248
}
249
});
250
```
251
252
#### onClone
253
254
Called when an element is cloned (in clone mode).
255
256
```javascript { .api }
257
/**
258
* Called when element is cloned
259
* @param evt - Event object with item (original) and clone properties
260
*/
261
onClone?: (evt: SortableEvent) => void;
262
```
263
264
#### onChange
265
266
Called when the dragging element changes position during drag.
267
268
```javascript { .api }
269
/**
270
* Called when dragging element changes position
271
* @param evt - Event object with newIndex property
272
*/
273
onChange?: (evt: SortableEvent) => void;
274
```
275
276
**Usage Examples:**
277
278
```javascript
279
Sortable.create(el, {
280
onChange: (evt) => {
281
console.log('Element moved to index:', evt.newIndex);
282
283
// Real-time preview of changes
284
updatePreview(evt.newIndex);
285
}
286
});
287
```
288
289
## Event Object Properties
290
291
```javascript { .api }
292
interface SortableEvent {
293
/** Target list element */
294
to: HTMLElement;
295
296
/** Source list element */
297
from: HTMLElement;
298
299
/** The dragged element */
300
item: HTMLElement;
301
302
/** Clone element (when using clone mode) */
303
clone?: HTMLElement;
304
305
/** Element's old index within parent */
306
oldIndex: number;
307
308
/** Element's new index within parent */
309
newIndex: number;
310
311
/** Element's old index within parent, only counting draggable elements */
312
oldDraggableIndex: number;
313
314
/** Element's new index within parent, only counting draggable elements */
315
newDraggableIndex: number;
316
317
/** Pull mode when item is in another sortable: "clone" if cloning, true if moving */
318
pullMode?: string | boolean;
319
320
/** Element on which have guided (onMove event only) */
321
related?: HTMLElement;
322
323
/** DOMRect of related element (onMove event only) */
324
relatedRect?: DOMRect;
325
326
/** DOMRect of dragged element (onMove event only) */
327
draggedRect?: DOMRect;
328
329
/** Whether Sortable will insert drag element after target by default (onMove event only) */
330
willInsertAfter?: boolean;
331
}
332
```
333
334
## Usage Patterns
335
336
### Complete Event Lifecycle
337
338
```javascript
339
Sortable.create(el, {
340
onChoose: (evt) => console.log('1. Item chosen'),
341
onStart: (evt) => console.log('2. Drag started'),
342
onChange: (evt) => console.log('3. Position changed'),
343
onEnd: (evt) => console.log('4. Drag ended'),
344
onAdd: (evt) => console.log('5a. Item added (if from another list)'),
345
onUpdate: (evt) => console.log('5b. Item updated (if same list)'),
346
onRemove: (evt) => console.log('5c. Item removed (if to another list)'),
347
onSort: (evt) => console.log('6. Any sort change occurred')
348
});
349
```
350
351
### Data Persistence
352
353
```javascript
354
Sortable.create(el, {
355
onEnd: (evt) => {
356
// Save to server
357
const newOrder = Array.from(evt.to.children)
358
.map(item => item.dataset.id);
359
360
fetch('/api/save-order', {
361
method: 'POST',
362
headers: { 'Content-Type': 'application/json' },
363
body: JSON.stringify({ order: newOrder })
364
});
365
}
366
});
367
```
368
369
### Cross-List Communication
370
371
```javascript
372
const lists = [el1, el2, el3].map(el =>
373
Sortable.create(el, {
374
group: 'shared',
375
onAdd: (evt) => {
376
console.log(`Item moved to list ${evt.to.id}`);
377
updateListCounters();
378
},
379
onRemove: (evt) => {
380
console.log(`Item left list ${evt.from.id}`);
381
updateListCounters();
382
}
383
})
384
);
385
```