or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdfile-editor.mdfile-management.mdindex.mdmodal-management.mdpanel-management.mdplugin-integration.md

plugin-integration.mddocs/

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

```