or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

event-management.mdfile-validation.mdindex.mdplugin-development.mdtype-system.mduppy-class.md

event-management.mddocs/

0

# Event Management

1

2

Uppy provides a comprehensive event system for handling all aspects of the file upload lifecycle. Events can be used for monitoring progress, implementing custom logic, and integrating with external systems.

3

4

## EventManager Class

5

6

Utility class for managing Uppy event subscriptions with automatic cleanup capabilities.

7

8

### Constructor

9

10

```typescript { .api }

11

constructor(uppy: Uppy<M, B>)

12

```

13

14

### Event Subscription

15

16

```typescript { .api }

17

on<K extends keyof UppyEventMap<M, B>>(

18

event: K,

19

fn: UppyEventMap<M, B>[K]

20

): Uppy<M, B>;

21

```

22

23

Subscribes to an event and tracks the subscription for later cleanup.

24

25

### Cleanup

26

27

```typescript { .api }

28

remove(): void;

29

```

30

31

Removes all event listeners registered through this EventManager instance.

32

33

### File-Specific Event Helpers

34

35

```typescript { .api }

36

onFilePause(fileID: UppyFile<M, B>['id'], cb: (isPaused: boolean) => void): void;

37

onFileRemove(fileID: UppyFile<M, B>['id'], cb: (isPaused: UppyFile<M, B>['id']) => void): void;

38

onPause(fileID: UppyFile<M, B>['id'], cb: (isPaused: boolean) => void): void;

39

onRetry(fileID: UppyFile<M, B>['id'], cb: () => void): void;

40

onRetryAll(fileID: UppyFile<M, B>['id'], cb: () => void): void;

41

onPauseAll(fileID: UppyFile<M, B>['id'], cb: () => void): void;

42

onCancelAll(fileID: UppyFile<M, B>['id'], eventHandler: UppyEventMap<M, B>['cancel-all']): void;

43

onResumeAll(fileID: UppyFile<M, B>['id'], cb: () => void): void;

44

```

45

46

These methods listen for global events but only trigger callbacks when they affect the specified file.

47

48

## Core Uppy Events

49

50

### File Events

51

52

```typescript { .api }

53

interface UppyEventMap<M extends Meta, B extends Body> {

54

'file-added': (file: UppyFile<M, B>) => void;

55

'file-removed': (file: UppyFile<M, B>) => void;

56

'files-added': (files: UppyFile<M, B>[]) => void;

57

}

58

```

59

60

**file-added**: Fired when a single file is added to Uppy

61

**file-removed**: Fired when a file is removed from Uppy

62

**files-added**: Fired when multiple files are added at once

63

64

### Upload Control Events

65

66

```typescript { .api }

67

interface UppyEventMap<M extends Meta, B extends Body> {

68

'upload': (uploadID: string, files: UppyFile<M, B>[]) => void;

69

'upload-start': (files: UppyFile<M, B>[]) => void;

70

'cancel-all': () => void;

71

'pause-all': () => void;

72

'resume-all': () => void;

73

'retry-all': (files: UppyFile<M, B>[]) => void;

74

}

75

```

76

77

**upload**: Fired when upload process begins

78

**upload-start**: Alternative event for upload start

79

**cancel-all**: Fired when all uploads are cancelled

80

**pause-all**: Fired when all uploads are paused

81

**resume-all**: Fired when all uploads are resumed

82

**retry-all**: Fired when retrying all failed uploads

83

84

### Upload Progress Events

85

86

```typescript { .api }

87

interface UppyEventMap<M extends Meta, B extends Body> {

88

'upload-progress': (

89

file: UppyFile<M, B> | undefined,

90

progress: FileProgressStarted

91

) => void;

92

'progress': (progress: number) => void;

93

'upload-success': (

94

file: UppyFile<M, B> | undefined,

95

response: NonNullable<UppyFile<M, B>['response']>

96

) => void;

97

'upload-error': (

98

file: UppyFile<M, B> | undefined,

99

error: { name: string; message: string; details?: string },

100

response?: Omit<NonNullable<UppyFile<M, B>['response']>, 'uploadURL'> | undefined

101

) => void;

102

}

103

```

104

105

**upload-progress**: Progress update for individual file upload

106

**progress**: Overall upload progress (0-100)

107

**upload-success**: File upload completed successfully

108

**upload-error**: File upload failed

109

110

### Upload State Events

111

112

```typescript { .api }

113

interface UppyEventMap<M extends Meta, B extends Body> {

114

'upload-pause': (file: UppyFile<M, B> | undefined, isPaused: boolean) => void;

115

'upload-retry': (file: UppyFile<M, B>) => void;

116

'upload-stalled': (

117

error: { message: string; details?: string },

118

files: UppyFile<M, B>[]

119

) => void;

120

}

121

```

122

123

**upload-pause**: File upload paused or resumed

124

**upload-retry**: File upload is being retried

125

**upload-stalled**: Upload appears to be stalled

126

127

### Processing Events

128

129

```typescript { .api }

130

interface UppyEventMap<M extends Meta, B extends Body> {

131

'preprocess-progress': (

132

file: UppyFile<M, B> | undefined,

133

progress: NonNullable<FileProgressStarted['preprocess']>

134

) => void;

135

'preprocess-complete': (

136

file: UppyFile<M, B> | undefined,

137

progress?: NonNullable<FileProgressStarted['preprocess']>

138

) => void;

139

'postprocess-progress': (

140

file: UppyFile<M, B> | undefined,

141

progress: NonNullable<FileProgressStarted['postprocess']>

142

) => void;

143

'postprocess-complete': (

144

file: UppyFile<M, B> | undefined,

145

progress?: NonNullable<FileProgressStarted['preprocess']>

146

) => void;

147

}

148

```

149

150

**preprocess-progress**: Progress update during file preprocessing

151

**preprocess-complete**: File preprocessing completed

152

**postprocess-progress**: Progress update during file postprocessing

153

**postprocess-complete**: File postprocessing completed

154

155

### Validation Events

156

157

```typescript { .api }

158

interface UppyEventMap<M extends Meta, B extends Body> {

159

'restriction-failed': (file: UppyFile<M, B> | undefined, error: Error) => void;

160

}

161

```

162

163

**restriction-failed**: File failed validation against restrictions

164

165

### State Management Events

166

167

```typescript { .api }

168

interface UppyEventMap<M extends Meta, B extends Body> {

169

'state-update': (

170

prevState: State<M, B>,

171

nextState: State<M, B>,

172

patch?: Partial<State<M, B>>

173

) => void;

174

}

175

```

176

177

**state-update**: Uppy state has changed

178

179

### Information Events

180

181

```typescript { .api }

182

interface UppyEventMap<M extends Meta, B extends Body> {

183

'info-visible': () => void;

184

'info-hidden': () => void;

185

}

186

```

187

188

**info-visible**: Info message is now visible to user

189

**info-hidden**: Info message has been hidden

190

191

### Network Events

192

193

```typescript { .api }

194

interface UppyEventMap<M extends Meta, B extends Body> {

195

'is-offline': () => void;

196

'is-online': () => void;

197

}

198

```

199

200

**is-offline**: Internet connection lost

201

**is-online**: Internet connection restored

202

203

### Plugin Events

204

205

```typescript { .api }

206

interface UppyEventMap<M extends Meta, B extends Body> {

207

'plugin-added': (plugin: UnknownPlugin<any, any>) => void;

208

'plugin-remove': (plugin: UnknownPlugin<any, any>) => void;

209

}

210

```

211

212

**plugin-added**: Plugin has been installed

213

**plugin-remove**: Plugin has been removed

214

215

### Restoration Events

216

217

```typescript { .api }

218

interface UppyEventMap<M extends Meta, B extends Body> {

219

restored: (pluginData: any) => void;

220

'restore-confirmed': () => void;

221

'restore-canceled': () => void;

222

}

223

```

224

225

**restored**: Upload state has been restored

226

**restore-confirmed**: User confirmed state restoration

227

**restore-canceled**: User canceled state restoration

228

229

## Event Usage Examples

230

231

### Basic Event Handling

232

233

```typescript

234

import Uppy from '@uppy/core';

235

236

const uppy = new Uppy();

237

238

// File lifecycle events

239

uppy.on('file-added', (file) => {

240

console.log('File added:', file.name, file.size);

241

});

242

243

uppy.on('file-removed', (file) => {

244

console.log('File removed:', file.name);

245

});

246

247

// Upload progress tracking

248

uppy.on('upload-progress', (file, progress) => {

249

if (file) {

250

console.log(`${file.name}: ${progress.bytesUploaded}/${progress.bytesTotal}`);

251

}

252

});

253

254

uppy.on('upload-success', (file, response) => {

255

console.log('Upload successful:', file?.name, response.body);

256

});

257

258

uppy.on('upload-error', (file, error, response) => {

259

console.error('Upload failed:', file?.name, error.message);

260

});

261

```

262

263

### Progress Monitoring

264

265

```typescript

266

let totalProgress = 0;

267

268

uppy.on('progress', (progress) => {

269

totalProgress = progress;

270

updateProgressBar(progress);

271

});

272

273

uppy.on('upload-start', (files) => {

274

console.log(`Starting upload of ${files.length} files`);

275

showProgressModal();

276

});

277

278

uppy.on('complete', (result) => {

279

console.log('Upload complete:', result);

280

hideProgressModal();

281

282

if (result.failed.length > 0) {

283

showErrorMessage(`${result.failed.length} files failed to upload`);

284

} else {

285

showSuccessMessage(`${result.successful.length} files uploaded successfully`);

286

}

287

});

288

289

function updateProgressBar(progress) {

290

const progressBar = document.querySelector('#progress-bar');

291

progressBar.style.width = `${progress}%`;

292

progressBar.textContent = `${Math.round(progress)}%`;

293

}

294

```

295

296

### File Validation Events

297

298

```typescript

299

uppy.on('restriction-failed', (file, error) => {

300

console.log('File restriction failed:', file?.name, error.message);

301

302

// Show custom error message to user

303

if (error.message.includes('size')) {

304

showNotification('File is too large', 'error');

305

} else if (error.message.includes('type')) {

306

showNotification('File type not allowed', 'error');

307

}

308

});

309

310

// Pre-upload validation

311

uppy.on('upload', (uploadID, files) => {

312

// Custom validation before upload starts

313

const invalidFiles = files.filter(file =>

314

!file.name.match(/^[a-zA-Z0-9_-]+\.[a-zA-Z0-9]+$/)

315

);

316

317

if (invalidFiles.length > 0) {

318

uppy.info('Some files have invalid names', 'error');

319

invalidFiles.forEach(file => uppy.removeFile(file.id));

320

}

321

});

322

```

323

324

### EventManager Usage

325

326

```typescript

327

import Uppy, { EventManager } from '@uppy/core';

328

329

class FileUploadComponent {

330

private uppy: Uppy;

331

private eventManager: EventManager<any, any>;

332

333

constructor() {

334

this.uppy = new Uppy();

335

this.eventManager = new EventManager(this.uppy);

336

this.setupEvents();

337

}

338

339

setupEvents() {

340

// All events registered through EventManager

341

this.eventManager.on('file-added', this.handleFileAdded);

342

this.eventManager.on('upload-success', this.handleUploadSuccess);

343

this.eventManager.on('upload-error', this.handleUploadError);

344

345

// File-specific event helpers

346

this.eventManager.onFilePause('specific-file-id', (isPaused) => {

347

console.log('File pause state changed:', isPaused);

348

});

349

}

350

351

handleFileAdded = (file) => {

352

// Update component state

353

this.updateFileList();

354

};

355

356

handleUploadSuccess = (file, response) => {

357

// Handle successful upload

358

this.processUploadResult(file, response);

359

};

360

361

handleUploadError = (file, error) => {

362

// Handle upload error

363

this.showErrorForFile(file, error);

364

};

365

366

destroy() {

367

// Clean up all event listeners at once

368

this.eventManager.remove();

369

this.uppy.destroy();

370

}

371

}

372

```

373

374

### State Monitoring

375

376

```typescript

377

uppy.on('state-update', (prevState, nextState, patch) => {

378

console.log('State updated:', patch);

379

380

// React to specific state changes

381

if (patch?.files) {

382

const fileIds = Object.keys(patch.files);

383

fileIds.forEach(fileId => {

384

const fileUpdate = patch.files[fileId];

385

if (fileUpdate.progress) {

386

updateFileProgress(fileId, fileUpdate.progress);

387

}

388

});

389

}

390

391

if (patch?.totalProgress !== undefined) {

392

updateOverallProgress(patch.totalProgress);

393

}

394

});

395

```

396

397

### Plugin Communication

398

399

```typescript

400

// Plugin emitting custom events

401

class MyPlugin extends BasePlugin {

402

doSomething() {

403

// Emit custom event

404

this.uppy.emit('my-plugin:action-completed', { data: 'result' });

405

}

406

}

407

408

// Listening for plugin events

409

uppy.on('my-plugin:action-completed', (result) => {

410

console.log('Plugin action completed:', result);

411

});

412

413

// Plugin lifecycle events

414

uppy.on('plugin-added', (plugin) => {

415

console.log('Plugin added:', plugin.id, plugin.type);

416

417

if (plugin.type === 'dashboard') {

418

// Configure dashboard plugin

419

plugin.setOptions({ theme: 'dark' });

420

}

421

});

422

```

423

424

### Network Status Handling

425

426

```typescript

427

uppy.on('is-offline', () => {

428

console.log('Connection lost');

429

uppy.info('Connection lost. Uploads will resume when back online.', 'warning');

430

pauseAllUploads();

431

});

432

433

uppy.on('is-online', () => {

434

console.log('Connection restored');

435

uppy.info('Connection restored. Resuming uploads.', 'success');

436

resumeAllUploads();

437

});

438

439

function pauseAllUploads() {

440

uppy.pauseAll();

441

showOfflineIndicator();

442

}

443

444

function resumeAllUploads() {

445

uppy.resumeAll();

446

hideOfflineIndicator();

447

}

448

```

449

450

## Event Best Practices

451

452

### Event Cleanup

453

Always remove event listeners when components are destroyed to prevent memory leaks:

454

455

```typescript

456

// Manual cleanup

457

const handler = (file) => console.log(file);

458

uppy.on('file-added', handler);

459

// Later...

460

uppy.off('file-added', handler);

461

462

// Or use EventManager for automatic cleanup

463

const eventManager = new EventManager(uppy);

464

eventManager.on('file-added', handler);

465

// Later...

466

eventManager.remove(); // Removes all managed listeners

467

```

468

469

### Error Handling

470

Wrap event handlers in try-catch blocks to prevent errors from breaking the upload process:

471

472

```typescript

473

uppy.on('upload-success', (file, response) => {

474

try {

475

processUploadResponse(file, response);

476

} catch (error) {

477

console.error('Error processing upload response:', error);

478

uppy.info('Upload succeeded but processing failed', 'warning');

479

}

480

});

481

```

482

483

### Performance Considerations

484

- Use debouncing for frequently fired events like `progress` and `upload-progress`

485

- Avoid heavy computations in event handlers

486

- Consider using `once()` for one-time event handling

487

488

```typescript

489

// Debounced progress handler

490

let progressTimeout;

491

uppy.on('progress', (progress) => {

492

clearTimeout(progressTimeout);

493

progressTimeout = setTimeout(() => {

494

updateProgressDisplay(progress);

495

}, 100);

496

});

497

```