File Upload
Drag-and-drop and click-to-browse file upload zone.
Dropzone — Multiple Files
Click the dropzone or drag files onto it. Images get a thumbnail preview; other files fall back to a generic icon. Each file shows a simulated upload progress bar and can be removed individually.
—
<div class="sc-fu" x-data="fileUpload({ multiple: true })">
<label class="sc-fu-dropzone" @click="$refs.fileInput.click()"
@drop.prevent="onDrop($event)" @dragover.prevent="isDragging = true">
<input type="file" multiple x-ref="fileInput" @change="onBrowse($event)" />
</label>
<template x-for="entry in files" :key="entry.id">
<div>...<button @click="remove(entry)">✕</button></div>
</template>
</div>
Single File — Image Only, 2MB Limit
Restricted to image/* and 2MB max. Selecting a second file
replaces the first; a rejected file shows the reason rather than
failing silently.
—
States
Empty, failed-upload, and disabled states.
Empty (no files yet)
Failed Upload
contract-final.pdf
Disabled
Progress here is simulated with setTimeout in
js/ui/components/form.js's _simulateProgress() — replace
that with real upload-progress events (XHR's progress event, or a
fetch-based upload library) when wiring this into a project. Everything else
(validation, thumbnails, drag state, removal) needs no changes.