File Upload
Live Demos HubFile Upload
Interactive production-grade hypermedia component for HTMXUI.
Interactive Preview
Click to upload or drag and drop
SVG, PNG, JPG or GIF (MAX. 800x400px)
HTML Source
<!--
Component: file-upload.html
Configurable State: themeColor ('primary'|'secondary'|'destructive'), size ('sm'|'md'|'lg'), isOpen (boolean)
Usage: Bind styles dynamically using hx-class="{ 'bg-primary': themeColor === 'primary' }" or hx-style="{ width: size === 'lg' ? '100%' : 'auto' }"
-->
<!-- Drag and Drop File Upload Component -->
<!-- Uses HTMX to instantly upload files on drop without JS. The backend handles the file and returns the updated state. -->
<div hx-ext="reactive" hx-state="{ themeColor: \'primary\', size: \'md\', isOpen: false }"
class="flex flex-col items-center justify-center w-full h-64 border-2 border-dashed border-border rounded-lg bg-muted/50 hover:bg-muted transition-colors cursor-pointer group"
hx-post="{upload_url}"
hx-trigger="drop"
hx-encoding="multipart/form-data"
hx-target="this"
hx-swap="outerHTML"
ondragover="event.preventDefault(); this.classList.add('border-primary', 'bg-accent')"
ondragleave="this.classList.remove('border-primary', 'bg-accent')"
ondrop="event.preventDefault(); this.classList.remove('border-primary', 'bg-accent'); htmx.trigger(this, 'drop', { files: event.dataTransfer.files })"
>
<div class="flex flex-col items-center justify-center pt-5 pb-6 pointer-events-none">
<svg class="w-10 h-10 mb-4 text-muted-foreground group-hover:text-primary transition-colors" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 16">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2"/>
</svg>
<p class="mb-2 text-sm text-muted-foreground"><span class="font-semibold text-foreground">Click to upload</span> or drag and drop</p>
<p class="text-xs text-muted-foreground">SVG, PNG, JPG or GIF (MAX. 800x400px)</p>
</div>
<!-- Hidden input allows fallback click-to-select behavior -->
<input type="file" name="file" class="hidden"
hx-post="{upload_url}"
hx-trigger="change"
hx-encoding="multipart/form-data"
hx-target="closest div"
hx-swap="outerHTML"
/>
</div>