Upload
File upload dropzone with drag-and-drop, file list, progress bars, and multiple variants.
Dropzone
Preview
Drop files here or browse
PNG, JPG, PDF up to 10MB
<div class="upload">
<div class="upload-dropzone">
<input type="file" class="upload-input" id="file-input" multiple>
<div class="upload-icon">
<svg xmlns="http://www.w3.org/2000/svg" class="size-12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg>
</div>
<p class="upload-text">Drop files here or <span class="upload-browse" onclick="document.getElementById('file-input').click()">browse</span></p>
<p class="upload-hint">PNG, JPG, PDF up to 10MB</p>
</div>
</div> Requires: ux.min.css
<div class="relative w-full">
<div class="flex flex-col items-center justify-center min-h-[200px] p-8 bg-base-100 border-2 border-dashed border-base-300 rounded-box cursor-pointer hover:border-primary transition-colors">
<input type="file" class="absolute w-0 h-0 opacity-0 pointer-events-none" multiple>
<svg class="size-12 mb-4 text-base-content/60" ...></svg>
<p class="font-medium text-base-content">Drop files here or <span class="text-primary font-medium cursor-pointer hover:underline">browse</span></p>
<p class="text-sm text-base-content/60">PNG, JPG, PDF up to 10MB</p>
</div>
</div> Requires: tw.min.css
// Handle drag events on dropzone:
// dropzone.addEventListener('dragover', (e) => {
// e.preventDefault();
// dropzone.classList.add('upload-dropzone-dragover');
// });
// dropzone.addEventListener('dragleave', () => {
// dropzone.classList.remove('upload-dropzone-dragover');
// });
// dropzone.addEventListener('drop', (e) => {
// e.preventDefault();
// const files = e.dataTransfer.files;
// // Process files...
// }); File List with Progress
Preview
photo.jpg
2.4 MBComplete
document.pdf
5.1 MB67%
large-video.mp4
150 MB
File exceeds maximum size (10MB)
<div class="upload">
<div class="upload-files">
<!-- Completed file -->
<div class="upload-file upload-file-success">
<div class="upload-preview">
<img src="https://picsum.photos/40" alt="Preview">
</div>
<div class="upload-file-info">
<div class="upload-file-name">photo.jpg</div>
<div class="upload-file-meta"><span>2.4 MB</span><span>Complete</span></div>
</div>
<div class="upload-file-actions">
<button class="upload-file-action upload-file-action-danger">
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
</button>
</div>
</div>
<!-- Uploading file -->
<div class="upload-file">
<div class="upload-preview">
<svg xmlns="http://www.w3.org/2000/svg" class="upload-preview-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14.5 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V7.5L14.5 2z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="upload-file-info">
<div class="upload-file-name">document.pdf</div>
<div class="upload-file-meta"><span>5.1 MB</span><span>67%</span></div>
<div class="upload-progress"><div class="upload-progress-bar" style="width: 67%;"></div></div>
</div>
</div>
<!-- Error file -->
<div class="upload-file upload-file-error">
<div class="upload-preview">
<svg xmlns="http://www.w3.org/2000/svg" class="upload-preview-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/></svg>
</div>
<div class="upload-file-info">
<div class="upload-file-name">large-video.mp4</div>
<div class="upload-file-meta"><span>150 MB</span></div>
<div class="upload-file-error-text">File exceeds maximum size (10MB)</div>
</div>
<div class="upload-file-actions">
<button class="upload-file-action upload-file-action-danger">
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
</div>
</div>
</div> Requires: ux.min.css
<div class="relative w-full">
<div class="flex flex-col gap-2 mt-4">
<!-- Completed file -->
<div class="flex items-center gap-4 px-4 py-2 bg-base-100 border border-success rounded-field">
<div class="flex items-center justify-center shrink-0 w-10 h-10 bg-base-200 rounded-field overflow-hidden">
<img src="https://picsum.photos/40" alt="Preview" class="w-full h-full object-cover">
</div>
<div class="flex-1 min-w-0">
<div class="text-sm font-medium text-base-content truncate">photo.jpg</div>
<div class="flex text-xs text-base-content/60 gap-2 mt-px"><span>2.4 MB</span><span>Complete</span></div>
</div>
<button class="flex items-center justify-center w-8 h-8 bg-transparent border-none rounded-field cursor-pointer text-base-content/60 hover:text-error hover:bg-error/10">
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>
</button>
</div>
<!-- Uploading file -->
<div class="flex items-center gap-4 px-4 py-2 bg-base-100 border border-base-300 rounded-field">
<div class="flex items-center justify-center shrink-0 w-10 h-10 bg-base-200 rounded-field">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-base-content/60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14.5 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V7.5L14.5 2z"/><polyline points="14 2 14 8 20 8"/></svg>
</div>
<div class="flex-1 min-w-0">
<div class="text-sm font-medium text-base-content truncate">document.pdf</div>
<div class="flex text-xs text-base-content/60 gap-2 mt-px"><span>5.1 MB</span><span>67%</span></div>
<div class="w-full h-1 bg-base-300 rounded-sm mt-1 overflow-hidden">
<div class="h-full bg-primary rounded-sm" style="width: 67%;"></div>
</div>
</div>
</div>
<!-- Error file -->
<div class="flex items-center gap-4 px-4 py-2 bg-error/5 border border-error rounded-field">
<div class="flex items-center justify-center shrink-0 w-10 h-10 bg-base-200 rounded-field">
<svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6 text-base-content/60" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/></svg>
</div>
<div class="flex-1 min-w-0">
<div class="text-sm font-medium text-base-content truncate">large-video.mp4</div>
<div class="flex text-xs text-base-content/60 gap-2 mt-px"><span>150 MB</span></div>
<div class="text-xs text-error mt-px">File exceeds maximum size (10MB)</div>
</div>
<button class="flex items-center justify-center w-8 h-8 bg-transparent border-none rounded-field cursor-pointer text-base-content/60 hover:text-error hover:bg-error/10">
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
</div>
</div> Requires: tw.min.css
// Update progress: progressBar.style.width = percent + '%';
// Mark complete: file.classList.add('upload-file-success');
// Mark error: file.classList.add('upload-file-error'); Compact & Button Variants
Preview
Drop files here or browse
Upload Files
<!-- Compact -->
<div class="upload upload-compact mb-4">
<div class="upload-dropzone">
<div class="upload-icon"><svg xmlns="http://www.w3.org/2000/svg" class="size-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg></div>
<div class="upload-content">
<p class="upload-text">Drop files here or browse</p>
</div>
</div>
</div>
<!-- Button style -->
<div class="upload upload-button">
<div class="upload-dropzone">
<div class="upload-icon"><svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg></div>
<p class="upload-text">Upload Files</p>
</div>
</div> Requires: ux.min.css
<!-- Compact -->
<div class="relative w-full mb-4">
<div class="flex flex-row items-center gap-4 px-6 py-4 bg-base-100 border-2 border-dashed border-base-300 rounded-box cursor-pointer hover:border-primary transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="size-6 text-base-content/60 shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg>
<p class="font-medium text-base-content text-left">Drop files here or browse</p>
</div>
</div>
<!-- Button style -->
<div class="relative inline-block">
<div class="inline-flex flex-row items-center gap-2 px-6 py-2 bg-primary text-primary-content rounded-field cursor-pointer hover:brightness-90 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12"/></svg>
<p class="font-medium">Upload Files</p>
</div>
</div> Requires: tw.min.css
// Same file input handling for all variants | Class | Description |
|---|---|
.upload | Container |
.upload-dropzone | Drop area with dashed border |
.upload-dropzone-dragover | Active drag state |
.upload-input | Hidden file input |
.upload-icon | Upload icon (48px) |
.upload-text | Main text |
.upload-hint | Hint/constraint text |
.upload-browse | Clickable "browse" link |
.upload-compact | Compact horizontal variant |
.upload-button | Button-style variant |
.upload-avatar | Circular avatar upload |
.upload-grid | Grid preview for files |
.upload-files | File list container |
.upload-file | File row |
.upload-file-success/error | File state variants |
.upload-progress | Progress track |
.upload-progress-bar | Progress fill bar |
.upload-file-action | File action button |
.upload-file-action-danger | Red action (delete) |