0
# Plugin Integration
1
2
Register and manage plugins that integrate with the dashboard interface.
3
4
## Capabilities
5
6
### Add Target
7
8
Register a plugin as a dashboard target for integration with the dashboard interface.
9
10
```typescript { .api }
11
/**
12
* Register plugin as dashboard target
13
* Only acquirer, progressindicator, and editor plugins are supported
14
* @param plugin - Plugin instance to register
15
* @returns Dashboard element for plugin mounting or null if invalid
16
*/
17
addTarget(plugin: UnknownPlugin): HTMLElement | null;
18
```
19
20
**Usage Examples:**
21
22
```typescript
23
import Dashboard from "@uppy/dashboard";
24
import GoogleDrive from "@uppy/google-drive";
25
import Webcam from "@uppy/webcam";
26
27
const dashboard = uppy.getPlugin("Dashboard") as Dashboard;
28
29
// Manual plugin registration
30
const googleDrive = new GoogleDrive(uppy, { /* options */ });
31
const dashboardElement = dashboard.addTarget(googleDrive);
32
33
// Automatic registration via plugin mounting
34
uppy.use(GoogleDrive, { /* options */ });
35
// Dashboard automatically calls addTarget for compatible plugins
36
37
// Custom plugin registration
38
class CustomAcquirer extends BasePlugin {
39
type = 'acquirer';
40
id = 'CustomAcquirer';
41
title = 'Custom Source';
42
43
mount(target, plugin) {
44
// Plugin-specific mounting logic
45
return dashboard.addTarget(this);
46
}
47
}
48
49
uppy.use(CustomAcquirer);
50
```
51
52
**Behavior:**
53
- Validates plugin type (must be 'acquirer', 'progressindicator', or 'editor')
54
- Creates target object with plugin ID, name, and type
55
- Adds target to dashboard state
56
- Returns dashboard element for plugin mounting
57
- Logs error and returns null for invalid plugin types
58
59
### Remove Target
60
61
Unregister a plugin target from the dashboard interface.
62
63
```typescript { .api }
64
/**
65
* Unregister plugin target
66
* Removes plugin from dashboard targets and cleans up state
67
* @param plugin - Plugin instance to unregister
68
*/
69
removeTarget(plugin: UnknownPlugin): void;
70
```
71
72
**Usage Examples:**
73
74
```typescript
75
// Remove plugin programmatically
76
const googleDrive = uppy.getPlugin("GoogleDrive");
77
if (googleDrive) {
78
dashboard.removeTarget(googleDrive);
79
}
80
81
// Remove plugin on uninstall
82
uppy.removePlugin(googleDrive);
83
// Dashboard automatically calls removeTarget
84
85
// Conditional plugin removal
86
function removePluginIfUnsupported(pluginId: string) {
87
const plugin = uppy.getPlugin(pluginId);
88
if (plugin && !plugin.isSupported?.()) {
89
dashboard.removeTarget(plugin);
90
uppy.removePlugin(plugin);
91
}
92
}
93
```
94
95
**Behavior:**
96
- Filters out the target with matching plugin ID
97
- Updates dashboard state to remove target
98
- Cleans up any active panels for the removed plugin
99
100
### Plugin Target Interface
101
102
Structure and requirements for plugin targets.
103
104
```typescript { .api }
105
/**
106
* Basic plugin target interface
107
*/
108
interface Target {
109
/** Unique plugin identifier */
110
id: string;
111
/** Human-readable plugin name */
112
name: string;
113
/** Plugin type classification */
114
type: 'acquirer' | 'progressindicator' | 'editor';
115
}
116
117
/**
118
* Enhanced target with render capabilities
119
*/
120
interface TargetWithRender extends Target {
121
/** Function to render plugin icon */
122
icon: () => ComponentChild;
123
/** Function to render plugin interface */
124
render: () => ComponentChild;
125
}
126
```
127
128
### Supported Plugin Types
129
130
Different types of plugins supported by the dashboard.
131
132
```typescript { .api }
133
/**
134
* Acquirer plugins - File source providers
135
* Provide interfaces for selecting files from various sources
136
*/
137
interface AcquirerPlugin {
138
type: 'acquirer';
139
/** Plugin identifier */
140
id: string;
141
/** Display name */
142
title?: string;
143
/** Check if plugin is supported in current environment */
144
isSupported?(): boolean;
145
/** Render plugin interface */
146
render(): ComponentChild;
147
/** Optional icon for plugin */
148
icon?(): ComponentChild;
149
/** Handle root-level paste events */
150
handleRootPaste?(event: ClipboardEvent): void;
151
/** Handle root-level drop events */
152
handleRootDrop?(event: DragEvent): void;
153
/** Check if plugin can handle root drop */
154
canHandleRootDrop?(event: DragEvent): boolean;
155
}
156
157
/**
158
* Progress indicator plugins - Upload progress display
159
* Provide custom progress visualization
160
*/
161
interface ProgressIndicatorPlugin {
162
type: 'progressindicator';
163
id: string;
164
title?: string;
165
render(): ComponentChild;
166
}
167
168
/**
169
* Editor plugins - File editing capabilities
170
* Provide file editing and manipulation interfaces
171
*/
172
interface EditorPlugin {
173
type: 'editor';
174
id: string;
175
title?: string;
176
/** Check if plugin can edit specific file */
177
canEditFile(file: UppyFile): boolean;
178
/** Select file for editing */
179
selectFile(file: UppyFile): void;
180
/** Save editor changes */
181
save(): void;
182
/** Render editor interface */
183
render(): ComponentChild;
184
}
185
```
186
187
### Automatic Plugin Discovery
188
189
Dashboard automatically discovers and integrates compatible plugins.
190
191
```typescript { .api }
192
/**
193
* Automatic plugin discovery system
194
*/
195
interface AutoDiscovery {
196
/** Discover plugins on Uppy plugin addition */
197
onPluginAdded(plugin: UnknownPlugin): void;
198
/** Remove targets on plugin removal */
199
onPluginRemoved(plugin: UnknownPlugin): void;
200
/** Add supported plugin if no target specified */
201
addSupportedPluginIfNoTarget(plugin: UnknownPlugin): void;
202
}
203
```
204
205
**Auto-Discovery Examples:**
206
207
```typescript
208
// Plugins are automatically discovered when added to Uppy
209
uppy.use(GoogleDrive, {
210
companionUrl: 'https://companion.uppy.io'
211
});
212
// Dashboard automatically integrates GoogleDrive
213
214
uppy.use(Webcam, {
215
modes: ['picture', 'video']
216
});
217
// Dashboard automatically integrates Webcam
218
219
// Manual control over auto-discovery
220
uppy.use(Dashboard, {
221
plugins: ['GoogleDrive', 'Webcam'] // Only these plugins will be integrated
222
});
223
224
// Disable auto-discovery by providing empty plugins array
225
uppy.use(Dashboard, {
226
plugins: [] // No automatic plugin integration
227
});
228
```
229
230
### Plugin Configuration Options
231
232
Configure which plugins are integrated with the dashboard.
233
234
```typescript { .api }
235
/**
236
* Plugin integration configuration
237
*/
238
interface PluginIntegrationConfig {
239
/** Array of plugin IDs to integrate (empty array disables auto-discovery) */
240
plugins?: string[];
241
/** Default icon for plugins without custom icons */
242
defaultPickerIcon?: typeof defaultPickerIcon;
243
}
244
```
245
246
**Configuration Examples:**
247
248
```typescript
249
// Specific plugin integration
250
uppy.use(Dashboard, {
251
plugins: ['GoogleDrive', 'Dropbox', 'Instagram'],
252
defaultPickerIcon: CustomIcon
253
});
254
255
// All compatible plugins (default behavior)
256
uppy.use(Dashboard, {
257
plugins: [] // Will auto-discover all compatible plugins
258
});
259
260
// No plugin integration
261
uppy.use(Dashboard, {
262
plugins: [], // Empty array disables auto-discovery
263
// Must manually call addTarget for any integrations
264
});
265
```
266
267
### Plugin State Management
268
269
State management for integrated plugins and their targets.
270
271
```typescript { .api }
272
/**
273
* Plugin state properties
274
*/
275
interface PluginState {
276
/** Array of registered plugin targets */
277
targets: Target[];
278
/** Currently active picker panel */
279
activePickerPanel: Target | undefined;
280
}
281
282
/**
283
* Plugin categorization helpers
284
*/
285
interface PluginCategories {
286
/** Get acquirer plugins (file sources) */
287
getAcquirers(targets: Target[]): TargetWithRender[];
288
/** Get progress indicator plugins */
289
getProgressIndicators(targets: Target[]): TargetWithRender[];
290
/** Get editor plugins */
291
getEditors(targets: Target[]): TargetWithRender[];
292
}
293
```
294
295
### Plugin Support Detection
296
297
Detect and handle plugin compatibility and support.
298
299
```typescript { .api }
300
/**
301
* Plugin support detection
302
*/
303
interface PluginSupport {
304
/** Check if plugin is supported in current environment */
305
isTargetSupported(target: Target): boolean;
306
/** Attach render functions to supported targets */
307
attachRenderFunctionToTarget(target: Target): TargetWithRender;
308
}
309
```
310
311
**Support Detection Examples:**
312
313
```typescript
314
// Plugin with support detection
315
class WebRTCPlugin extends BasePlugin {
316
type = 'acquirer';
317
318
isSupported(): boolean {
319
return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
320
}
321
}
322
323
// Conditional plugin loading
324
async function loadCompatiblePlugins() {
325
const plugins = [
326
{ Plugin: GoogleDrive, supported: () => true },
327
{ Plugin: Webcam, supported: () => !!navigator.mediaDevices },
328
{ Plugin: ScreenCapture, supported: () => !!navigator.mediaDevices.getDisplayMedia }
329
];
330
331
for (const { Plugin, supported } of plugins) {
332
if (supported()) {
333
uppy.use(Plugin);
334
}
335
}
336
}
337
338
// Runtime support checking
339
function checkPluginSupport() {
340
const dashboard = uppy.getPlugin('Dashboard');
341
const state = dashboard.getPluginState();
342
343
state.targets.forEach(target => {
344
const plugin = uppy.getPlugin(target.id);
345
if (plugin.isSupported && !plugin.isSupported()) {
346
console.warn(`Plugin ${target.id} is not supported in this environment`);
347
dashboard.removeTarget(plugin);
348
}
349
});
350
}
351
```
352
353
### Plugin Events and Communication
354
355
Event system for plugin communication and lifecycle management.
356
357
```typescript { .api }
358
/**
359
* Plugin lifecycle events
360
*/
361
interface PluginLifecycleEvents {
362
/** Plugin added to Uppy */
363
'plugin-added': (plugin: UnknownPlugin) => void;
364
/** Plugin removed from Uppy */
365
'plugin-remove': (plugin: UnknownPlugin) => void;
366
}
367
```
368
369
**Event Examples:**
370
371
```typescript
372
// Listen for plugin lifecycle
373
uppy.on('plugin-added', (plugin) => {
374
console.log(`Plugin added: ${plugin.id}`);
375
if (plugin.type === 'acquirer') {
376
setupAcquirerIntegration(plugin);
377
}
378
});
379
380
uppy.on('plugin-remove', (plugin) => {
381
console.log(`Plugin removed: ${plugin.id}`);
382
cleanupPluginIntegration(plugin);
383
});
384
385
// Plugin communication
386
function setupPluginCommunication() {
387
const dashboard = uppy.getPlugin('Dashboard');
388
const googleDrive = uppy.getPlugin('GoogleDrive');
389
390
if (googleDrive) {
391
googleDrive.on('folder-selected', (folder) => {
392
dashboard.showPanel('GoogleDrive');
393
});
394
395
googleDrive.on('files-selected', (files) => {
396
dashboard.hideAllPanels();
397
});
398
}
399
}
400
```
401
402
### Custom Plugin Development
403
404
Guidelines for developing plugins compatible with dashboard integration.
405
406
```typescript { .api }
407
/**
408
* Custom plugin development interface
409
*/
410
interface CustomPluginRequirements {
411
/** Unique plugin identifier */
412
id: string;
413
/** Plugin type for dashboard integration */
414
type: 'acquirer' | 'progressindicator' | 'editor';
415
/** Human-readable title */
416
title?: string;
417
/** Render function for plugin interface */
418
render(): ComponentChild;
419
/** Optional icon function */
420
icon?(): ComponentChild;
421
/** Optional support detection */
422
isSupported?(): boolean;
423
/** Mount function for dashboard integration */
424
mount?(target: any, plugin: any): HTMLElement | null;
425
}
426
```
427
428
**Custom Plugin Examples:**
429
430
```typescript
431
// Custom file source plugin
432
class CustomCloudStorage extends BasePlugin {
433
static VERSION = '1.0.0';
434
435
type = 'acquirer';
436
id = 'CustomCloudStorage';
437
title = 'My Cloud Storage';
438
439
constructor(uppy, opts) {
440
super(uppy, opts);
441
this.id = this.opts.id || 'CustomCloudStorage';
442
}
443
444
isSupported() {
445
return typeof window !== 'undefined' && window.fetch;
446
}
447
448
mount(target, plugin) {
449
const dashboard = target;
450
return dashboard.addTarget(this);
451
}
452
453
render() {
454
return h('div', { className: 'custom-cloud-storage' }, [
455
h('h3', null, 'Select from My Cloud Storage'),
456
h('button', {
457
onclick: this.openFilePicker.bind(this)
458
}, 'Browse Files')
459
]);
460
}
461
462
icon() {
463
return h('svg', { /* icon properties */ }, [
464
// SVG paths for custom icon
465
]);
466
}
467
468
async openFilePicker() {
469
const files = await this.fetchFilesFromAPI();
470
files.forEach(file => this.uppy.addFile(file));
471
}
472
}
473
474
// Usage
475
uppy.use(CustomCloudStorage, {
476
apiKey: 'your-api-key',
477
serverUrl: 'https://api.example.com'
478
});
479
```
480
481
### Plugin Integration Best Practices
482
483
Recommended patterns for plugin integration and development.
484
485
```typescript { .api }
486
/**
487
* Integration best practices
488
*/
489
interface IntegrationBestPractices {
490
/** Provide meaningful plugin IDs and titles */
491
naming: 'Use descriptive, unique identifiers';
492
/** Implement proper support detection */
493
supportDetection: 'Check environment capabilities';
494
/** Handle errors gracefully */
495
errorHandling: 'Provide user-friendly error messages';
496
/** Clean up resources properly */
497
cleanup: 'Remove event listeners and clean state';
498
/** Follow accessibility guidelines */
499
accessibility: 'Support keyboard navigation and screen readers';
500
/** Provide consistent user experience */
501
ux: 'Match dashboard styling and interaction patterns';
502
}
503
```
504
505
**Best Practice Examples:**
506
507
```typescript
508
class WellDesignedPlugin extends BasePlugin {
509
constructor(uppy, opts) {
510
super(uppy, opts);
511
this.id = this.opts.id || 'WellDesignedPlugin';
512
this.title = this.opts.title || 'Well Designed Plugin';
513
514
// Validate required options
515
if (!this.opts.apiKey) {
516
throw new Error('WellDesignedPlugin: apiKey is required');
517
}
518
}
519
520
isSupported() {
521
return !!(window.fetch && window.FileReader);
522
}
523
524
mount(target, plugin) {
525
this.target = target;
526
return target.addTarget(this);
527
}
528
529
unmount() {
530
if (this.target) {
531
this.target.removeTarget(this);
532
}
533
this.cleanup();
534
}
535
536
cleanup() {
537
// Clean up event listeners, timers, etc.
538
if (this.pollInterval) {
539
clearInterval(this.pollInterval);
540
}
541
}
542
543
render() {
544
return h('div', {
545
className: 'uppy-Plugin-panel',
546
'aria-label': `${this.title} file picker`
547
}, [
548
this.renderContent()
549
]);
550
}
551
552
handleError(error) {
553
this.uppy.log(`[${this.id}] ${error.message}`, 'error');
554
this.uppy.info(`${this.title}: ${error.message}`, 'error');
555
}
556
}
557
```