Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more.
—
Upload handler plugins manage the actual file upload process, supporting various protocols and destinations including resumable uploads, traditional HTTP uploads, and cloud storage services.
Protocols that support resumable uploads for reliability and performance.
/**
* Tus resumable upload protocol implementation
*/
class Tus<M extends Meta = {}, B extends Body = {}> extends BasePlugin<TusOptions> {
constructor(uppy: Uppy<M, B>, options?: TusOptions);
}
interface TusOptions {
endpoint: string;
headers?: { [key: string]: string };
chunkSize?: number;
withCredentials?: boolean;
overridePatchMethod?: boolean;
retryDelays?: number[];
parallelUploads?: number;
removeFingerprintOnSuccess?: boolean;
uploadDataDuringCreation?: boolean;
urlStorage?: TusUrlStorage;
fileReader?: TusFileReader;
onBeforeRequest?: (req: HttpRequest) => void;
onAfterResponse?: (req: HttpRequest, res: HttpResponse) => void;
limit?: number;
onShouldRetry?: (err: Error, retryAttempt: number, options: TusOptions) => boolean;
metaFields?: string[];
allowedMetaFields?: string[];
locale?: Locale;
}
interface TusUrlStorage {
findAllUploads(): Promise<{ [key: string]: string }>;
findUploadsByFingerprint(fingerprint: string): Promise<string[]>;
removeUpload(urlStorageKey: string): Promise<void>;
addUpload(fingerprint: string, upload: { uploadUrl: string; urlStorageKey: string }): Promise<void>;
}
interface TusFileReader {
slice(file: Blob, start: number, end: number): Blob;
}Usage Example:
import { Uppy, Tus } from "uppy";
const uppy = new Uppy()
.use(Tus, {
endpoint: 'https://tusd.tusdemo.net/files/',
chunkSize: 1024 * 1024, // 1MB chunks
retryDelays: [0, 1000, 3000, 5000],
parallelUploads: 3,
removeFingerprintOnSuccess: true,
headers: {
'Authorization': 'Bearer ' + authToken
},
onBeforeRequest: (req) => {
// Modify request before sending
req.setHeader('X-Custom-Header', 'value');
},
onAfterResponse: (req, res) => {
// Handle response
console.log('Upload progress response:', res.getStatus());
}
});Standard HTTP upload implementations using XMLHttpRequest or fetch.
/**
* XHR upload implementation for standard HTTP endpoints
*/
class XHRUpload<M extends Meta = {}, B extends Body = {}> extends BasePlugin<XHRUploadOptions<M, B>> {
constructor(uppy: Uppy<M, B>, options?: XHRUploadOptions<M, B>);
}
interface XHRUploadOptions<M extends Meta = {}, B extends Body = {}> {
endpoint: string;
method?: 'POST' | 'PUT' | 'PATCH';
formData?: boolean;
fieldName?: string;
allowedMetaFields?: string[];
headers?: { [key: string]: string } | ((file: UppyFile<M, B>) => { [key: string]: string });
bundle?: boolean;
withCredentials?: boolean;
timeout?: number;
limit?: number;
responseType?: '' | 'text' | 'json' | 'blob' | 'document' | 'arraybuffer';
responseUrlFieldName?: string;
getResponseData?: (responseText: string, response: XMLHttpRequest) => B;
getResponseError?: (responseText: string, response: XMLHttpRequest) => Error;
onBeforeRequest?: (xhr: XMLHttpRequest, file: UppyFile<M, B>) => void;
validateStatus?: (status: number, responseText: string, response: XMLHttpRequest) => boolean;
locale?: Locale;
}Usage Examples:
// Standard form data upload
uppy.use(XHRUpload, {
endpoint: '/api/upload',
method: 'POST',
formData: true,
fieldName: 'file',
headers: {
'X-CSRF-Token': csrfToken
},
allowedMetaFields: ['name', 'caption', 'description'],
limit: 5, // Max 5 concurrent uploads
timeout: 30000, // 30 second timeout
onBeforeRequest: (xhr, file) => {
// Add file-specific headers
xhr.setRequestHeader('X-File-Name', file.name);
xhr.setRequestHeader('X-File-Size', file.size.toString());
},
getResponseData: (responseText, response) => {
// Parse custom response format
return JSON.parse(responseText);
},
validateStatus: (status, responseText, response) => {
// Custom success validation
return status >= 200 && status < 300;
}
});
// JSON upload with custom headers per file
uppy.use(XHRUpload, {
endpoint: '/api/files',
method: 'PUT',
formData: false,
headers: (file) => ({
'Content-Type': file.type,
'X-File-ID': file.id,
'Authorization': `Bearer ${getTokenForFile(file)}`
}),
responseType: 'json'
});Direct upload to cloud storage services bypassing your server.
/**
* AWS S3 direct upload implementation
*/
class AwsS3<M extends Meta = {}, B extends Body = {}> extends BasePlugin<AwsS3Options> {
constructor(uppy: Uppy<M, B>, options?: AwsS3Options);
}
interface AwsS3Options {
companionUrl?: string;
companionHeaders?: { [key: string]: string };
companionCookiesRule?: string;
getUploadParameters?: (file: UppyFile<any, any>) => Promise<S3UploadParameters> | S3UploadParameters;
timeout?: number;
limit?: number;
metaFields?: string[];
allowedMetaFields?: string[];
locale?: Locale;
}
interface S3UploadParameters {
method?: 'POST' | 'PUT';
url: string;
fields?: { [key: string]: string };
headers?: { [key: string]: string };
}Usage Examples:
// S3 upload with companion server
uppy.use(AwsS3, {
companionUrl: 'https://companion.uppy.io',
limit: 3,
timeout: 60000
});
// S3 upload with custom parameters
uppy.use(AwsS3, {
getUploadParameters: async (file) => {
// Get signed URL from your server
const response = await fetch('/api/s3-params', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
filename: file.name,
contentType: file.type,
size: file.size
})
});
const data = await response.json();
return {
method: 'POST',
url: data.url,
fields: data.fields,
headers: data.headers
};
},
allowedMetaFields: ['caption', 'description'],
limit: 5
});Upload handlers that integrate with file processing and encoding services.
/**
* Transloadit encoding service integration
*/
class Transloadit<M extends Meta = {}, B extends Body = {}> extends BasePlugin<TransloaditOptions> {
constructor(uppy: Uppy<M, B>, options?: TransloaditOptions);
}
interface TransloaditOptions {
assemblyOptions?: AssemblyOptions | ((file: UppyFile<M, B>) => AssemblyOptions);
waitForEncoding?: boolean;
waitForMetadata?: boolean;
alwaysRunAssembly?: boolean;
importFromUploadURLs?: boolean;
signature?: string;
params?: AssemblyParameters | ((file: UppyFile<M, B>) => AssemblyParameters);
fields?: { [key: string]: string } | ((file: UppyFile<M, B>) => { [key: string]: string });
limit?: number;
locale?: Locale;
}
interface AssemblyOptions {
params: AssemblyParameters;
signature?: string;
fields?: { [key: string]: string };
}
interface AssemblyParameters {
auth: {
key: string;
expires?: string;
};
template_id?: string;
steps?: { [key: string]: StepOptions };
notify_url?: string;
}
interface StepOptions {
robot: string;
use?: string | string[];
[key: string]: any;
}Usage Example:
// Transloadit with template
uppy.use(Transloadit, {
params: {
auth: { key: 'YOUR_TRANSLOADIT_KEY' },
template_id: 'YOUR_TEMPLATE_ID'
},
waitForEncoding: true,
// Dynamic assembly options per file
assemblyOptions: (file) => ({
params: {
auth: { key: 'YOUR_TRANSLOADIT_KEY' },
steps: {
resize: {
robot: '/image/resize',
width: file.meta.targetWidth || 800,
height: file.meta.targetHeight || 600,
resize_strategy: 'fit'
},
optimize: {
robot: '/image/optimize',
use: 'resize'
}
}
}
})
});// Upload lifecycle events
interface UploadHandlerEvents<M extends Meta = {}, B extends Body = {}> {
'upload-started': (file: UppyFile<M, B>) => void;
'upload-progress': (file: UppyFile<M, B>, progress: FileProgress) => void;
'upload-success': (file: UppyFile<M, B>, response: UploadSuccessResponse<B>) => void;
'upload-error': (file: UppyFile<M, B>, error: Error, response?: UploadErrorResponse<M, B>) => void;
'upload-retry': (file: UppyFile<M, B>) => void;
}
// Tus-specific events
interface TusEvents<M extends Meta = {}, B extends Body = {}> {
'tus:upload-created': (file: UppyFile<M, B>, upload: { uploadURL: string }) => void;
'tus:chunk-uploaded': (file: UppyFile<M, B>, chunk: { chunkNumber: number, chunkSize: number }) => void;
}
// S3-specific events
interface AwsS3Events<M extends Meta = {}, B extends Body = {}> {
's3:upload-created': (file: UppyFile<M, B>, upload: S3Upload) => void;
's3:upload-progress': (file: UppyFile<M, B>, progress: S3Progress) => void;
}interface UploadSuccessResponse<B extends Body = {}> {
status: number;
body: B;
uploadURL?: string;
}
interface UploadErrorResponse<M extends Meta = {}, B extends Body = {}> {
status: number;
body: any;
message?: string;
details?: string;
}
interface HttpRequest {
getMethod(): string;
getURL(): string;
setHeader(name: string, value: string): void;
getHeader(name: string): string | undefined;
setProgressHandler(handler: (bytesSent: number, bytesTotal: number) => void): void;
}
interface HttpResponse {
getStatus(): number;
getHeader(name: string): string | undefined;
getBody(): string;
}Install with Tessl CLI
npx tessl i tessl/npm-uppy