File Upload
Drag and drop or click to upload files with preview and progress indication.
Default Drop Zone
Large dashed border area for dragging and dropping files.
html
Drag & drop files here
or
SVG, PNG, JPG or GIF (max. 800x400px)
<div class="vt-w-full vt-max-w-lg vt-border-2 vt-border-dashed vt-border-border-default vt-rounded-lg vt-p-12 vt-flex vt-flex-col vt-items-center vt-justify-center vt-text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-cloud-upload vt-w-10 vt-h-10 vt-text-foreground-muted vt-mb-4">
<path d="M12 13v8"></path><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"></path><path d="m8 17 4-4 4 4"></path>
</svg>
<p class="vt-text-sm vt-font-medium vt-mb-1">Drag & drop files here</p>
<p class="vt-text-xs vt-text-foreground-muted vt-mb-4">or</p>
<button class="vt-btn vt-btn-primary">
Browse Files
</button>
<p class="vt-text-xs vt-text-foreground-muted vt-mt-4">SVG, PNG, JPG or GIF (max. 800x400px)</p>
</div>
With File List
Drop zone with a list of uploaded files showing progress.
html
Drag & drop files here
or
banner-hero.png
2.4 MB
presentation.pdf
8.1 MB
demo-video.mp4
24.7 MB
<div class="vt-max-w-lg vt-mx-auto">
<!-- Drop zone -->
<div class="vt-border-2 vt-border-dashed vt-border-border-default vt-rounded-lg vt-p-8 vt-flex vt-flex-col vt-items-center vt-justify-center vt-text-center vt-mb-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-cloud-upload vt-w-10 vt-h-10 vt-text-foreground-muted vt-mb-4">
<path d="M12 13v8"></path><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"></path><path d="m8 17 4-4 4 4"></path>
</svg>
<p class="vt-text-sm vt-font-medium vt-mb-1">Drag & drop files here</p>
<p class="vt-text-xs vt-text-foreground-muted vt-mb-3">or</p>
<button class="vt-btn vt-btn-primary">
Browse Files
</button>
</div>
<!-- File list -->
<div class="vt-space-y-2">
<!-- File 1 - 100% complete -->
<div class="vt-flex vt-items-center vt-gap-3 vt-p-3 vt-rounded-2xl vt-border vt-border-border-default">
<div class="vt-icon-badge vt-w-8 vt-h-8 vt-rounded-lg vt-bg-surface-moderate">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-image vt-w-4 vt-h-4 vt-text-foreground-muted">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
</div>
<div class="vt-flex-1 vt-min-w-0">
<div class="vt-flex vt-justify-between vt-items-center vt-mb-1">
<span class="vt-text-sm vt-font-medium vt-truncate">banner-hero.png</span>
<span class="vt-text-xs vt-text-foreground-muted">2.4 MB</span>
</div>
<div class="vt-w-full vt-h-1.5 vt-rounded-full vt-bg-surface-subtle">
<div class="vt-h-1.5 vt-rounded-full vt-transition-all vt-w-full vt-bg-success-fill"></div>
</div>
</div>
<div class="vt-shrink-0 vt-text-success-fill">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-check vt-w-5 vt-h-5">
<path d="M20 6 9 17l-5-5"></path>
</svg>
</div>
</div>
<!-- File 2 - 60% -->
<div class="vt-flex vt-items-center vt-gap-3 vt-p-3 vt-rounded-2xl vt-border vt-border-border-default">
<div class="vt-icon-badge vt-w-8 vt-h-8 vt-rounded-lg vt-bg-surface-moderate">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-file-text vt-w-4 vt-h-4 vt-text-foreground-muted">
<path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path><path d="M10 9H8"></path><path d="M16 13H8"></path><path d="M16 17H8"></path>
</svg>
</div>
<div class="vt-flex-1 vt-min-w-0">
<div class="vt-flex vt-justify-between vt-items-center vt-mb-1">
<span class="vt-text-sm vt-font-medium vt-truncate">presentation.pdf</span>
<span class="vt-text-xs vt-text-foreground-muted">8.1 MB</span>
</div>
<div class="vt-w-full vt-h-1.5 vt-rounded-full vt-bg-surface-subtle">
<div class="vt-bg-info-fill vt-h-1.5 vt-rounded-full vt-transition-all vt-inline-86d5a62908"></div>
</div>
</div>
<button class="vt-shrink-0 vt-text-foreground-muted vt-hover:text-foreground-primary vt-transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-x vt-w-4 vt-h-4">
<path d="M18 6 6 18"></path><path d="m6 6 12 12"></path>
</svg>
</button>
</div>
<!-- File 3 - 30% -->
<div class="vt-flex vt-items-center vt-gap-3 vt-p-3 vt-rounded-2xl vt-border vt-border-border-default">
<div class="vt-icon-badge vt-w-8 vt-h-8 vt-rounded-lg vt-bg-surface-moderate">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-video vt-w-4 vt-h-4 vt-text-foreground-muted">
<path d="m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5"></path><rect x="2" y="6" width="14" height="12" rx="2"></rect>
</svg>
</div>
<div class="vt-flex-1 vt-min-w-0">
<div class="vt-flex vt-justify-between vt-items-center vt-mb-1">
<span class="vt-text-sm vt-font-medium vt-truncate">demo-video.mp4</span>
<span class="vt-text-xs vt-text-foreground-muted">24.7 MB</span>
</div>
<div class="vt-w-full vt-h-1.5 vt-rounded-full vt-bg-surface-subtle">
<div class="vt-bg-info-fill vt-h-1.5 vt-rounded-full vt-transition-all vt-inline-6528b2713f"></div>
</div>
</div>
<button class="vt-shrink-0 vt-text-foreground-muted vt-hover:text-foreground-primary vt-transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-x vt-w-4 vt-h-4">
<path d="M18 6 6 18"></path><path d="m6 6 12 12"></path>
</svg>
</button>
</div>
</div>
</div>
Compact
Small inline button for attaching files.
html
<button class="vt-btn vt-btn-bordered">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-paperclip vt-w-4 vt-h-4 vt-mr-2">
<path d="m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"></path>
</svg>
Attach files
</button>
Image Preview
Drop zone for images with a preview grid below.
html
Drop images here
PNG, JPG or WebP up to 10MB
<div class="vt-max-w-lg vt-mx-auto">
<!-- Drop zone -->
<div class="vt-border-2 vt-border-dashed vt-border-border-default vt-rounded-lg vt-p-8 vt-flex vt-flex-col vt-items-center vt-justify-center vt-text-center vt-mb-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-image vt-w-10 vt-h-10 vt-text-foreground-muted vt-mb-4">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
<p class="vt-text-sm vt-font-medium vt-mb-1">Drop images here</p>
<p class="vt-text-xs vt-text-foreground-muted">PNG, JPG or WebP up to 10MB</p>
</div>
<!-- Preview grid -->
<div class="vt-flex vt-items-center vt-gap-3">
<!-- Preview 1 -->
<div class="vt-w-24 vt-h-24 vt-rounded-lg vt-bg-surface-moderate vt-flex vt-items-center vt-justify-center vt-relative">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-image vt-w-8 vt-h-8 vt-text-foreground-muted">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
</div>
<!-- Preview 2 -->
<div class="vt-w-24 vt-h-24 vt-rounded-lg vt-bg-surface-moderate vt-flex vt-items-center vt-justify-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-image vt-w-8 vt-h-8 vt-text-foreground-muted">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
</div>
<!-- Preview 3 -->
<div class="vt-w-24 vt-h-24 vt-rounded-lg vt-bg-surface-moderate vt-flex vt-items-center vt-justify-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-image vt-w-8 vt-h-8 vt-text-foreground-muted">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><circle cx="9" cy="9" r="2"></circle><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path>
</svg>
</div>
<!-- Add more -->
<div class="vt-w-24 vt-h-24 vt-rounded-lg vt-border-2 vt-border-dashed vt-border-border-default vt-flex vt-items-center vt-justify-center vt-cursor-pointer vt-hover:border-info-fill vt-hover:bg-info-fill/5 vt-transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-plus vt-w-8 vt-h-8 vt-text-foreground-muted">
<path d="M5 12h14"></path><path d="M12 5v14"></path>
</svg>
</div>
</div>
</div>
Drag Active State
Visual feedback when files are being dragged over the drop zone.
html
Release to upload
<div class="vt-w-full vt-max-w-lg vt-border-2 vt-border-dashed vt-border-info-fill vt-rounded-lg vt-p-12 vt-bg-info-fill/5 vt-flex vt-flex-col vt-items-center vt-justify-center vt-text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-cloud-upload vt-w-10 vt-h-10 vt-text-info-fill vt-mb-4">
<path d="M12 13v8"></path><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"></path><path d="m8 17 4-4 4 4"></path>
</svg>
<p class="vt-text-sm vt-font-medium vt-text-info-fill">Release to upload</p>
</div>
Guidelines
Drag-and-drop upload zone with browse fallback and file-chip results.
Drag & drop files here
Do
Drag & drop files here
Don't
presentation.pdf
Do
presentation.pdf
Don't
API Reference
All CSS classes available for the File Upload component.
| Class | Type | Description |
|---|---|---|
vt-border-2 vt-border-dashed |
Border | Dashed border style for the drop zone area |
vt-border-border-default |
Border | Default border color for inactive drop zone |
vt-border-info-fill |
Border | Blue border for active drag-over state |
vt-bg-info-fill/5 |
Color | Subtle blue background for drag-active state |
vt-rounded-lg |
Shape | Rounded corners for drop zone and file items |
vt-rounded-2xl |
Shape | Larger radius for file list items |
vt-bg-surface-moderate |
Color | Muted background for file type icon containers |
vt-bg-surface-subtle |
Color | Subtle background for progress bar track |
vt-bg-info-fill |
Color | Blue fill for upload progress bar |
vt-h-1.5 vt-rounded-full |
Shape | Thin rounded progress bar height |
vt-text-foreground-muted |
Color | Muted text for helper text and file sizes |
vt-text-info-fill |
Color | Blue text for drag-active state label |
vt-hover:border-info-fill |
Interactive | Blue border on hover for add-more button |
Accessibility
Keyboard and screen reader support.
| Feature | Details |
|---|---|
| Label | The drop zone should have an accessible label describing expected file types |
| Keyboard | Drop zone is focusable and activatable via Enter/Space to open file picker |
| Feedback | Announce upload status changes (uploading, complete, error) via aria-live |
| Drag and drop | Provide keyboard alternative since drag-and-drop is not accessible |