Vanilla UI Kit Upload v1.0.0 · toast →

Uploads, one file.

A zero-dependency dropzone with a managed file list — click, drag, or paste; thumbnails, validation, progress, and retry. Every card below is live.

Basic single file

One file at a time; picking another replaces it. Keyboard: Tab to the zone, Enter or Space opens the picker.

new Upload('#box')

Multiple + image thumbnails

Drop a few images — previews render from object URLs (revoked on remove). Paste works too while the zone is focused.

new Upload('#box', {
  multiple: true,
  accept: 'image/*'
})

Validation errors

Images only, max 200 KB, max 3 files. Rejected files get an inline danger row — nothing throws, valid files still land.

new Upload('#box', {
  multiple: true,
  accept: 'image/*',
  maxSize: 200 * 1024,   // '200 KB' in the error
  maxFiles: 3
})

Custom upload fn + retry

A simulated uploader with progress. Files whose name contains fail reject — the row gets a retry button (a retry succeeds). Or use the buttons to add sample files.

new Upload('#box', {
  multiple: true,
  upload: function (file, onProgress) {   // onProgress(0..1)
    return fakeServer(file, onProgress)   // → Promise
  },
  onDone: (file, res) => log(file.name + ' → ' + res.url)
})
// built-in XHR uploader instead:
//   upload: { action: '/api/upload', fieldName: 'file' }

Enhance an input in a real <form>

The original <input type=file> is wrapped and hidden but keeps submitting with the form — dragged files are mirrored onto it. Submit to see what the form would send.

new Upload(document.getElementById('attachments'))
// destroy() restores the native input exactly

Family theming

With the VC core loaded, one call themes every component.

VC.config({ accent: '#b45309' })
// standalone: .vup { --vup-accent: #b45309 }