Plugin

uploady.js

Drop-in Filestack-style file staging for <input type="file">. Users drop files or folders, rename or remove before submit, and your backend gets a clean FormData.

npm install @goboldlyforward/uploady

Try it

Drop, review, submit

Drop files, a folder, or click browse. Each file cascades into the staging list with its size and type. Hover a row to rename, click × to remove, drop more onto the list to keep adding. Hit Submit to see exactly what would be posted.

Form payload


    

Install & usage

Drop it in

One stylesheet, one script, one attribute. No build step. Plugin auto-mounts on DOMContentLoaded.

<link rel="stylesheet" href="path/to/uploady.css">
<script src="path/to/uploady.js"></script>

<form action="/uploads" method="post" enctype="multipart/form-data">
  <input type="file" name="docs" multiple
         accept="image/*,.pdf"
         data-uploady
         data-max-files="20"
         data-max-size="10485760">
  <button>Submit</button>
</form>

The plugin keeps the original <input> in the DOM and syncs its files list to whatever the user has staged. A normal form post sends every staged file under the input's name — your backend reads it like any other multi-file upload.

Drop a folder and uploady recursively flattens it: every file inside becomes one entry, folder structure discarded. Set data-retain-folders="true" to show the relative path next to each file (the file itself is still posted by its leaf name — browsers don't allow the original webkit-relative path to round-trip through input.files).

Options

Tune it with data attributes

All options are data-* attributes on the file input. Standard HTML attributes — multiple, accept — are honored.

AttributeDefaultWhat it does
data-retain-folders false If true, shows the relative path of each file in a dropped folder. If false (default), folders are silently flattened and only files are kept.
data-animate true Cascade each new file into the list with a progress-bar staging animation. Set false to drop files in instantly.
data-allow-rename true Show a pencil icon on hover; click (or double-click the name) to rename inline. Enter commits, Escape cancels. Extension is preserved.
data-allow-remove true Show a × on each file. Click to remove it from the staged set before submit.
data-max-files Cap the number of files. Extras are silently skipped and a notice appears.
data-max-size Per-file byte limit. Oversized files appear in an error state and are excluded from the form post.
accept Standard HTML attribute — comma-separated MIME types and/or extensions. Files that don't match show an error and are excluded from the form post.
multiple Standard HTML attribute. Without it, uploady runs in single-file mode: each new pick replaces the prior file.

JavaScript API

For when auto-init isn't enough

// Manual init (after injecting new file inputs)
Uploady.initAll(scope);            // scan a subtree for [data-uploady]
Uploady.init(inputElement);        // mount one input

// Live instance
const inst = Uploady.instances.get(inputElement);
inst.getFiles();                   // -> File[] (excludes errored)
inst.getEntries();                 // -> [{ id, file, status, error, relPath }]
inst.removeFile(id);               // drop a file from the staged set
inst.renameFile(id, "new.pdf");    // rebuild the File with a new name
inst.reset();                      // back to the empty dropzone

// Events bubble from the original input
input.addEventListener('uploady:files-added', (e) => {
  console.log(e.detail.added, e.detail.all);
});
input.addEventListener('uploady:file-removed', (e) => {
  console.log(e.detail.id, e.detail.file);
});
input.addEventListener('uploady:file-renamed', (e) => {
  console.log(e.detail.oldName, '→', e.detail.newName);
});
input.addEventListener('uploady:reset', () => { ... });