v1.1.1

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 &amp; 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 &amp; 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
Always pair drag-and-drop with a Browse button fallback.

Drag & drop files here

Don't
Don't rely on drag-and-drop alone — it fails on touch and keyboard.
presentation.pdf
Do
Show per-file progress and a control to remove each file.
presentation.pdf
Don't
Don't leave uploads without status or a way to cancel.

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
Built with: