Universal UI plugin for Uppy file uploader providing comprehensive dashboard interface with drag-and-drop, file previews, metadata editing, and progress tracking.
—
Handle file selection, metadata editing, and file operations within the dashboard.
Add files to the uploader with automatic metadata detection and validation.
/**
* Add files to the uploader
* Handles file validation, metadata extraction, and error handling
* @param files - Array of File objects to add
*/
addFiles(files: File[]): void;Usage Examples:
import Dashboard from "@uppy/dashboard";
const dashboard = uppy.getPlugin("Dashboard") as Dashboard;
// Add files from input element
const fileInput = document.getElementById("file-input") as HTMLInputElement;
fileInput.addEventListener("change", (event) => {
const files = Array.from(event.target.files || []);
dashboard.addFiles(files);
});
// Add files from drag and drop
function handleDrop(event: DragEvent) {
event.preventDefault();
const files = Array.from(event.dataTransfer?.files || []);
dashboard.addFiles(files);
}
// Add files programmatically
async function addFromCustomSource() {
const customFiles = await fetchFilesFromAPI();
const fileObjects = customFiles.map(data => new File([data.blob], data.name));
dashboard.addFiles(fileObjects);
}Behavior:
Save metadata for a specific file and close the file card interface.
/**
* Save file metadata
* Updates file metadata and closes file card interface
* @param meta - Metadata object to save
* @param fileID - ID of the file to update
*/
saveFileCard(meta: Meta, fileID: string): void;Usage Examples:
// Save file metadata from form
function saveFileMetadata(fileId: string, formData: FormData) {
const metadata = {
name: formData.get("title") as string,
caption: formData.get("caption") as string,
altText: formData.get("altText") as string
};
dashboard.saveFileCard(metadata, fileId);
}
// Save metadata with validation
function saveWithValidation(fileId: string, metadata: any) {
// Validate required fields
const requiredFields = uppy.opts.restrictions.requiredMetaFields || [];
const missing = requiredFields.filter(field => !metadata[field]);
if (missing.length > 0) {
console.error("Missing required fields:", missing);
return;
}
dashboard.saveFileCard(metadata, fileId);
}
// Programmatic metadata saving
uppy.on("file-added", (file) => {
// Auto-populate metadata for certain file types
if (file.type?.startsWith("image/")) {
const autoMetadata = {
altText: `Image: ${file.name}`,
category: "image"
};
dashboard.saveFileCard(autoMetadata, file.id);
}
});Behavior:
uppy.setFileMeta() to update file metadatatoggleFileCard(false, fileID) to close the file cardControl the display and interaction with individual file metadata cards.
/**
* Toggle file card visibility for specific file
* @param show - Whether to show or hide the file card
* @param fileID - ID of the file to show card for
*/
private toggleFileCard(show: boolean, fileID: string): void;File Card State:
/**
* File card related state properties
*/
interface FileCardState {
/** File ID for which card is shown, null if no card is active */
fileCardFor: string | null;
/** Whether file editor is currently shown */
showFileEditor: boolean;
/** Active overlay type */
activeOverlayType: 'FileCard' | 'FileEditor' | null;
}Configure metadata fields for file information collection.
/**
* Metadata field configuration
*/
interface MetaField {
/** Unique field identifier */
id: string;
/** Display name for the field */
name: string;
/** Placeholder text for input field */
placeholder?: string;
/** Custom render function for field */
render?: (field: FieldRenderOptions, h: PreactRender) => VNode<any>;
}
/**
* Field render options passed to custom render functions
*/
interface FieldRenderOptions {
/** Current field value */
value: string;
/** Function to update field value */
onChange: (newVal: string) => void;
/** CSS classes for field styling */
fieldCSSClasses: { text: string };
/** Whether field is required */
required: boolean;
/** Form identifier */
form: string;
}Metadata Configuration Examples:
// Static metadata fields
uppy.use(Dashboard, {
metaFields: [
{
id: "title",
name: "Title",
placeholder: "Enter file title"
},
{
id: "description",
name: "Description",
placeholder: "Describe this file"
},
{
id: "tags",
name: "Tags",
placeholder: "Comma-separated tags"
}
]
});
// Dynamic metadata fields based on file type
uppy.use(Dashboard, {
metaFields: (file) => {
const baseFields = [
{ id: "title", name: "Title", placeholder: "Enter title" }
];
if (file.type?.startsWith("image/")) {
return [
...baseFields,
{ id: "altText", name: "Alt Text", placeholder: "Describe the image" },
{ id: "caption", name: "Caption" }
];
} else if (file.type?.startsWith("video/")) {
return [
...baseFields,
{ id: "transcript", name: "Transcript" },
{ id: "duration", name: "Duration" }
];
}
return baseFields;
}
});
// Custom field rendering
uppy.use(Dashboard, {
metaFields: [
{
id: "priority",
name: "Priority",
render: (field, h) => {
return h('select', {
value: field.value,
onChange: (e) => field.onChange(e.target.value),
className: field.fieldCSSClasses.text
}, [
h('option', { value: '' }, 'Select priority'),
h('option', { value: 'low' }, 'Low'),
h('option', { value: 'medium' }, 'Medium'),
h('option', { value: 'high' }, 'High')
]);
}
}
]
});Events related to file management operations.
/**
* File management events
*/
interface DashboardFileEvents<M extends Meta, B extends Body> {
/** Emitted when file card editing starts */
"dashboard:file-edit-start": (file?: UppyFile<M, B>) => void;
/** Emitted when file card editing completes */
"dashboard:file-edit-complete": (file?: UppyFile<M, B>) => void;
}Event Usage Examples:
// Track file editing
uppy.on("dashboard:file-edit-start", (file) => {
console.log(`Started editing: ${file?.name}`);
// Show editing indicators, disable other actions, etc.
});
uppy.on("dashboard:file-edit-complete", (file) => {
console.log(`Finished editing: ${file?.name}`);
// Hide editing indicators, enable other actions, etc.
});
// Auto-save drafts during editing
let editingFile: UppyFile | null = null;
uppy.on("dashboard:file-edit-start", (file) => {
editingFile = file;
startAutoSave();
});
uppy.on("dashboard:file-edit-complete", () => {
editingFile = null;
stopAutoSave();
});
function startAutoSave() {
const interval = setInterval(() => {
if (editingFile) {
// Save current form state as draft
saveDraft(editingFile.id);
}
}, 30000); // Save every 30 seconds
}Built-in file validation and restriction handling.
/**
* File validation is handled by Uppy core
* Dashboard respects these restriction options:
*/
interface UppyRestrictions {
/** Allowed file types (MIME types or extensions) */
allowedFileTypes?: string[];
/** Maximum number of files */
maxNumberOfFiles?: number;
/** Maximum file size in bytes */
maxFileSize?: number;
/** Minimum file size in bytes */
minFileSize?: number;
/** Required metadata fields */
requiredMetaFields?: string[];
}Validation Examples:
// Configure file restrictions
const uppy = new Uppy({
restrictions: {
allowedFileTypes: ['.jpg', '.jpeg', '.png', '.gif'],
maxNumberOfFiles: 5,
maxFileSize: 10 * 1024 * 1024, // 10MB
requiredMetaFields: ['title', 'description']
}
});
// Handle validation errors
uppy.on('restriction-failed', (file, error) => {
console.error(`File ${file?.name} rejected:`, error.message);
// Show user-friendly error message
showErrorMessage(error.message);
});
// Custom validation
function validateFileContent(file: File): Promise<boolean> {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => {
// Custom validation logic
const content = e.target?.result;
const isValid = performCustomValidation(content);
resolve(isValid);
};
reader.readAsArrayBuffer(file);
});
}Integration with file processing and transformation.
/**
* File processing integration points
*/
interface FileProcessing {
/** Generate thumbnails for files */
handleRequestThumbnail(file: UppyFile): void;
/** Cancel thumbnail generation */
handleCancelThumbnail(file: UppyFile): void;
/** Wait for thumbnails before upload */
waitForThumbnailsBeforeUpload?: boolean;
}Processing Examples:
// Configure thumbnail generation
uppy.use(Dashboard, {
thumbnailWidth: 300,
thumbnailHeight: 300,
thumbnailType: 'image/jpeg',
waitForThumbnailsBeforeUpload: true
});
// Custom file processing
uppy.on('file-added', async (file) => {
if (file.type?.startsWith('image/')) {
// Extract EXIF data
const exifData = await extractExifData(file.data);
uppy.setFileMeta(file.id, {
...file.meta,
exif: exifData,
location: exifData.gps
});
}
});
// Process files before upload
uppy.on('preprocess-progress', (file, progress) => {
console.log(`Processing ${file.name}: ${progress.uploadProgress}%`);
});
uppy.on('preprocess-complete', (file) => {
console.log(`Finished processing: ${file.name}`);
});Built-in drag and drop functionality for file selection.
/**
* Drag and drop event handlers
*/
interface DragDropHandlers {
/** Handle drag over events */
onDragOver?: (event: DragEvent) => void;
/** Handle drag leave events */
onDragLeave?: (event: DragEvent) => void;
/** Handle drop events */
onDrop?: (event: DragEvent) => void;
}Drag and Drop Examples:
// Custom drag and drop behavior
uppy.use(Dashboard, {
onDragOver: (event) => {
console.log('Files being dragged over dashboard');
// Add visual feedback
event.currentTarget.classList.add('drag-active');
},
onDragLeave: (event) => {
console.log('Drag left dashboard area');
// Remove visual feedback
event.currentTarget.classList.remove('drag-active');
},
onDrop: (event) => {
console.log('Files dropped on dashboard');
// Custom drop handling
const files = Array.from(event.dataTransfer?.files || []);
// Additional processing before adding files
files.forEach(file => preprocessFile(file));
}
});
// Drag and drop validation
function validateDropEvent(event: DragEvent): boolean {
const items = event.dataTransfer?.items;
if (!items) return false;
// Check if all items are files
for (let i = 0; i < items.length; i++) {
if (items[i].kind !== 'file') {
return false;
}
}
return true;
}Install with Tessl CLI
npx tessl i tessl/npm-uppy--dashboard