0
# Plugins
1
2
Extensible plugin architecture for advanced functionality like multi-drag, auto-scroll, and element swapping.
3
4
## Capabilities
5
6
### Plugin Registration
7
8
Mount plugins to extend Sortable functionality before creating sortable instances.
9
10
```javascript { .api }
11
/**
12
* Mount one or more plugins to extend Sortable functionality
13
* @param plugins - Plugin instances to register
14
*/
15
Sortable.mount(...plugins: SortablePlugin[]): void;
16
```
17
18
**Usage Examples:**
19
20
```javascript
21
import Sortable, { MultiDrag, AutoScroll, Swap, OnSpill } from "sortablejs";
22
23
// Mount individual plugins
24
Sortable.mount(new MultiDrag());
25
Sortable.mount(new AutoScroll());
26
27
// Mount multiple plugins at once
28
Sortable.mount(new MultiDrag(), new AutoScroll(), new Swap());
29
30
// Now create sortables with plugin functionality
31
const sortable = Sortable.create(el, {
32
multiDrag: true, // MultiDrag plugin option
33
selectedClass: 'selected',
34
scroll: true, // AutoScroll plugin option
35
scrollSensitivity: 100
36
});
37
```
38
39
### MultiDrag Plugin
40
41
Enables selection and simultaneous dragging of multiple elements.
42
43
```javascript { .api }
44
/**
45
* MultiDrag plugin options
46
*/
47
interface MultiDragOptions {
48
/** Enable multi-drag functionality */
49
multiDrag?: boolean;
50
51
/** CSS class for selected elements */
52
selectedClass?: string;
53
54
/** Key to hold for multi-selection (e.g., 'ctrl', 'meta') */
55
multiDragKey?: string | null;
56
57
/** Avoid implicit deselection when clicking outside */
58
avoidImplicitDeselect?: boolean;
59
}
60
```
61
62
**Usage Examples:**
63
64
```javascript
65
import Sortable, { MultiDrag } from "sortablejs";
66
67
Sortable.mount(new MultiDrag());
68
69
const sortable = Sortable.create(el, {
70
multiDrag: true,
71
selectedClass: 'selected',
72
multiDragKey: 'ctrl', // Ctrl+click to select multiple
73
74
onSelect: (evt) => {
75
console.log('Item selected:', evt.item);
76
},
77
78
onDeselect: (evt) => {
79
console.log('Item deselected:', evt.item);
80
}
81
});
82
83
// Programmatically select items
84
sortable.select(document.getElementById('item1'));
85
sortable.select(document.getElementById('item2'));
86
87
// Get selected items
88
const selected = sortable.selectedElements; // HTMLElement[]
89
90
// Deselect all
91
sortable.deselectAll();
92
```
93
94
### AutoScroll Plugin
95
96
Automatically scrolls containers when dragging near edges.
97
98
```javascript { .api }
99
/**
100
* AutoScroll plugin options
101
*/
102
interface AutoScrollOptions {
103
/** Enable auto-scrolling */
104
scroll?: boolean;
105
106
/** Auto-scroll container (defaults to window) */
107
scrollSensitivity?: number;
108
109
/** Auto-scroll speed */
110
scrollSpeed?: number;
111
112
/** Pixels from edge to trigger scrolling */
113
bubbleScroll?: boolean;
114
}
115
```
116
117
**Usage Examples:**
118
119
```javascript
120
import Sortable, { AutoScroll } from "sortablejs";
121
122
Sortable.mount(new AutoScroll());
123
124
const sortable = Sortable.create(el, {
125
scroll: true,
126
scrollSensitivity: 100, // 100px from edge triggers scroll
127
scrollSpeed: 20, // Scroll speed
128
bubbleScroll: true // Allow scrolling in nested containers
129
});
130
```
131
132
### Swap Plugin
133
134
Enables element swapping instead of insertion-based reordering.
135
136
```javascript { .api }
137
/**
138
* Swap plugin options
139
*/
140
interface SwapOptions {
141
/** Enable swap mode instead of insertion */
142
swap?: boolean;
143
144
/** CSS class applied to swap target */
145
swapClass?: string;
146
}
147
```
148
149
**Usage Examples:**
150
151
```javascript
152
import Sortable, { Swap } from "sortablejs";
153
154
Sortable.mount(new Swap());
155
156
const sortable = Sortable.create(el, {
157
swap: true,
158
swapClass: 'highlight-swap',
159
160
onSwap: (evt) => {
161
console.log('Elements swapped:', evt.item, evt.swapItem);
162
}
163
});
164
```
165
166
### OnSpill Plugin
167
168
Handles elements that are dragged outside valid drop zones.
169
170
```javascript { .api }
171
/**
172
* OnSpill plugin options
173
*/
174
interface OnSpillOptions {
175
/** Remove element when dragged outside valid drop zone */
176
removeOnSpill?: boolean;
177
178
/** Revert element to original position when spilled */
179
revertOnSpill?: boolean;
180
}
181
```
182
183
**Usage Examples:**
184
185
```javascript
186
import Sortable, { OnSpill } from "sortablejs";
187
188
Sortable.mount(new OnSpill());
189
190
const sortable = Sortable.create(el, {
191
removeOnSpill: true, // Remove element when dragged out
192
193
onSpill: (evt) => {
194
console.log('Element spilled:', evt.item);
195
// Custom handling for spilled elements
196
}
197
});
198
199
// Alternative: revert instead of remove
200
const revertSortable = Sortable.create(el2, {
201
revertOnSpill: true, // Return to original position when spilled
202
});
203
```
204
205
## Plugin Events
206
207
### MultiDrag Events
208
209
Additional events available when MultiDrag plugin is active.
210
211
```javascript { .api }
212
/** Called when an element is selected for multi-drag */
213
onSelect?: (evt: SortableEvent) => void;
214
215
/** Called when an element is deselected */
216
onDeselect?: (evt: SortableEvent) => void;
217
```
218
219
### Swap Events
220
221
Additional events available when Swap plugin is active.
222
223
```javascript { .api }
224
/** Called when two elements are swapped */
225
onSwap?: (evt: SortableEvent & { swapItem: HTMLElement }) => void;
226
```
227
228
### OnSpill Events
229
230
Additional events available when OnSpill plugin is active.
231
232
```javascript { .api }
233
/** Called when an element is dragged outside a valid drop zone */
234
onSpill?: (evt: SortableEvent) => void;
235
```
236
237
## Custom Plugin Development
238
239
### Plugin Interface
240
241
Structure for creating custom Sortable plugins.
242
243
```javascript { .api }
244
interface SortablePlugin {
245
/** Plugin name (must be unique) */
246
name: string;
247
248
/** Default options merged into Sortable defaults */
249
defaults?: { [key: string]: any };
250
251
/** Event options configuration for plugin events */
252
eventOptions?: { [key: string]: any };
253
254
/** Option change listeners for dynamic configuration */
255
optionListeners?: { [optionName: string]: (value: any) => any };
256
257
/** Plugin utilities to extend Sortable.utils */
258
utils?: { [key: string]: any };
259
260
/** Custom event properties injected into SortableEvent */
261
eventProperties?: (eventName: string) => { [key: string]: any };
262
263
/** Initialize plugin on sortable instance creation */
264
initializePlugin?: (sortable: Sortable) => void;
265
266
/** Plugin-specific methods available on sortable instance */
267
[key: string]: any;
268
}
269
```
270
271
**Custom Plugin Example:**
272
273
```javascript
274
// Comprehensive custom plugin demonstrating all interface features
275
const AdvancedLoggerPlugin = {
276
name: 'advancedLogger',
277
278
// Default options merged into Sortable defaults
279
defaults: {
280
logLevel: 'info',
281
logToConsole: true,
282
logToServer: false,
283
serverEndpoint: '/api/drag-logs'
284
},
285
286
// Custom utilities added to Sortable.utils
287
utils: {
288
formatLogMessage: (level, action, item) => {
289
return `[${new Date().toISOString()}] ${level.toUpperCase()}: ${action} - ${item.textContent}`;
290
}
291
},
292
293
// Custom event properties injected into all events
294
eventProperties: function(eventName) {
295
return {
296
logTimestamp: Date.now(),
297
sessionId: this.sessionId
298
};
299
},
300
301
// Option change listeners for dynamic reconfiguration
302
optionListeners: {
303
logLevel: function(newLevel) {
304
console.log(`Logger level changed to: ${newLevel}`);
305
return newLevel;
306
}
307
},
308
309
// Initialize plugin on sortable instance
310
initializePlugin(sortable) {
311
// Generate unique session ID
312
this.sessionId = Math.random().toString(36).substr(2, 9);
313
314
// Store reference for event handlers
315
const plugin = this;
316
const options = sortable.options;
317
318
// Enhanced logging methods on sortable instance
319
sortable.logDragAction = function(action, item) {
320
const message = plugin.utils.formatLogMessage(options.logLevel, action, item);
321
322
if (options.logToConsole) {
323
console.log(message);
324
}
325
326
if (options.logToServer) {
327
fetch(options.serverEndpoint, {
328
method: 'POST',
329
headers: { 'Content-Type': 'application/json' },
330
body: JSON.stringify({
331
sessionId: plugin.sessionId,
332
action,
333
timestamp: Date.now(),
334
item: item.textContent
335
})
336
});
337
}
338
};
339
340
// Hook into events
341
const originalOnStart = options.onStart;
342
const originalOnEnd = options.onEnd;
343
344
options.onStart = (evt) => {
345
sortable.logDragAction('DRAG_START', evt.item);
346
originalOnStart && originalOnStart(evt);
347
};
348
349
options.onEnd = (evt) => {
350
sortable.logDragAction('DRAG_END', evt.item);
351
originalOnEnd && originalOnEnd(evt);
352
};
353
}
354
};
355
356
// Mount and use the advanced plugin
357
Sortable.mount(AdvancedLoggerPlugin);
358
359
const sortable = Sortable.create(el, {
360
logLevel: 'debug',
361
logToServer: true,
362
serverEndpoint: '/api/custom-logs',
363
364
onAdd: (evt) => {
365
// Custom event properties are automatically available
366
console.log('Session ID:', evt.sessionId);
367
console.log('Log timestamp:', evt.logTimestamp);
368
}
369
});
370
371
// Plugin methods are available on sortable instance
372
sortable.logDragAction('CUSTOM_ACTION', document.getElementById('item1'));
373
374
// Plugin utilities are available globally
375
console.log(Sortable.utils.formatLogMessage('warn', 'TEST', { textContent: 'Test Item' }));
376
```
377
378
## Plugin Combinations
379
380
### Comprehensive Setup
381
382
Example showing multiple plugins working together.
383
384
```javascript
385
import Sortable, { MultiDrag, AutoScroll, Swap, OnSpill } from "sortablejs";
386
387
// Mount all plugins
388
Sortable.mount(new MultiDrag(), new AutoScroll(), new Swap(), new OnSpill());
389
390
const sortable = Sortable.create(el, {
391
// MultiDrag options
392
multiDrag: true,
393
selectedClass: 'selected',
394
multiDragKey: 'ctrl',
395
396
// AutoScroll options
397
scroll: true,
398
scrollSensitivity: 100,
399
scrollSpeed: 20,
400
401
// Swap options (mutually exclusive with normal sorting)
402
// swap: true,
403
// swapClass: 'highlight-swap',
404
405
// OnSpill options
406
revertOnSpill: true,
407
408
// Event handlers for plugin functionality
409
onSelect: (evt) => console.log('Selected:', evt.item),
410
onDeselect: (evt) => console.log('Deselected:', evt.item),
411
onSpill: (evt) => console.log('Spilled:', evt.item)
412
});
413
```
414
415
## Available Plugins Summary
416
417
```javascript { .api }
418
/**
419
* MultiDrag - Select and drag multiple elements simultaneously
420
*/
421
class MultiDrag implements SortablePlugin {
422
name: 'multiDrag';
423
select(element: HTMLElement): void;
424
deselect(element: HTMLElement): void;
425
deselectAll(): void;
426
selectedElements: HTMLElement[];
427
}
428
429
/**
430
* AutoScroll - Automatic scrolling when dragging near container edges
431
*/
432
class AutoScroll implements SortablePlugin {
433
name: 'autoScroll';
434
}
435
436
/**
437
* Swap - Element swapping instead of insertion-based reordering
438
*/
439
class Swap implements SortablePlugin {
440
name: 'swap';
441
}
442
443
/**
444
* OnSpill - Handle elements dragged outside valid drop zones
445
*/
446
class OnSpill implements SortablePlugin {
447
name: 'onSpill';
448
}
449
```