webdevpuneet.com

File Dropzone — Free HTML CSS JS Drag & Drop Snippet

File Dropzone · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

<div class="demo">
  <div class="dropzone" id="zone">
    <div class="zone-inner" id="inner">
      <div class="zone-icon">📂</div>
      <p class="zone-title">Drop files here</p>
      <p class="zone-sub">or <label class="browse" for="file-input">browse files</label></p>
      <p class="zone-types">PNG, JPG, PDF, ZIP — up to 10 MB</p>
      <input type="file" id="file-input" multiple hidden onchange="handleFiles(this.files)" />
    </div>
  </div>
  <ul class="file-list" id="file-list"></ul>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

dragover + e.preventDefault() to allow drop, .over class for visual feedback
dragleave removes .over; drop reads e.dataTransfer.files
click-to-browse: zone onclick triggers hidden input.click()
Both drag and click paths call the same addFiles(files) function
extColors map assigns semantic colour badges per file extension
File size formatted as KB to one decimal place
Per-item remove button calls item.remove() from the DOM
.over .zone-icon { transform: scale(1.1) } on drag-over hover
Export as HTML file, React JSX, or React + Tailwind CSS
Live split-pane editor — preview updates as you type

About this UI Snippet

File Dropzone — dragover/drop Events, extColors Map & Click-to-Browse

Screenshot of the File Dropzone snippet rendered live

A file dropzone is a drag-and-drop upload area that also supports click-to-browse. Users drag files from their desktop onto the zone or click it to open the file picker. This is the standard upload UI for image editors, document processors, email attachments, and any file-based workflow — pair it with upload progress bars, the styled file input, or a media upload grid.

The drag events

dragover calls e.preventDefault() (required to allow drop) and adds .over to the zone — this triggers the dashed border colour change and the zone icon scale animation. dragleave removes .over. drop calls e.preventDefault() and reads e.dataTransfer.files — a FileList of dropped files.

Click-to-browse fallback

The zone has an onclick that calls input.click() on a hidden <input type="file" multiple>. This opens the OS file picker. The input's onchange handler passes this.files to the same addFiles() function — identical behaviour for both drag-and-drop and click paths.

The extColors map

extColors maps file extensions to colours: pdf → red, png/jpg → green, zip → yellow, mp4 → indigo, mp3 → violet, doc → blue. ext.toLowerCase() extracts the extension from the filename. If the extension is not in the map, a default slate colour is used. This colour is applied as an inline badge next to the filename.

File size formatting

(file.size / 1024).toFixed(1) + ' KB' formats the byte count to one decimal place.

Removing files

Each file item has a remove button. Its onclick calls item.remove() to delete the list item from the DOM.

The dragover/drop event pair

Without e.preventDefault() in the dragover handler, the browser's default action (opening the file) fires and no drop event is triggered. Always call e.preventDefault() in dragover to signal to the browser that this element accepts drops. The drop handler also calls e.preventDefault() to prevent the browser from navigating to the dropped file. e.dataTransfer.files provides the FileList of dropped files.

The visual drag-over state

The .drag-over class adds a coloured border and light background to communicate to the user that the zone is ready to accept the dropped file. This class is added in ondragover and removed in ondragleave. Adding a CSS transition: border-color 0.15s, background 0.15s to the dropzone makes the state change feel responsive.

File size and type validation

After receiving files (from drop or input change), validate before processing: const MAX_SIZE = 25 * 1024 * 1024; const ALLOWED = ['png','jpg','pdf','zip']; const valid = file.size <= MAX_SIZE && ALLOWED.includes(ext(file.name)). Show an error state for invalid files: an error badge with the reason ("File too large" or "Invalid type") instead of a progress bar. This prevents users from uploading incompatible files before the upload starts.

Step by step

How to Use

  1. 1
    Drag a file onto the zoneDrag any file from your desktop onto the dropzone in the preview. The border highlights on hover and the file appears in the list below.
  2. 2
    Click to browseClick the dropzone without dragging to open the OS file picker. Selected files appear in the same list.
  3. 3
    Add or remove file type coloursIn the JS panel, update the extColors map with your file types and brand colours.
  4. 4
    Restrict accepted file typesAdd accept="image/*,.pdf" to the hidden <input type="file"> element to filter the file picker.
  5. 5
    Wire to a real uploadIn addFiles(), create a FormData object, append each file, and call fetch("/upload", { method: "POST", body: formData }) to send files to your backend.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Document and image upload forms
Drop the dropzone into any form requiring file upload. Wire addFiles() to a FormData fetch for instant file submission without a library.
Email attachment selection
Use in a compose email interface to let users attach files. The extColors map visually distinguishes attachment types.
Learn drag-and-drop and DataTransfer API
Edit the dragover, dragleave, and drop handlers in the JS panel to understand how drag events and e.dataTransfer.files work.
Prototype file upload UX
Use the snippet to prototype how users will interact with file uploads before wiring a real backend. Test drag and click paths.
Custom file type badge colours
Update the extColors map with your own extension-to-colour mapping to match your design system.
Multi-file upload with preview
Extend the file list items to show image previews using FileReader.readAsDataURL for image files.
Related: Interest Selector
See the Interest Selector for a related forms pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

The dragover handler calls e.preventDefault() — without this the browser blocks the drop. The drop handler reads e.dataTransfer.files which is a FileList of all dragged files. addFiles() iterates over it to build the file list UI.

A hidden <input type="file" multiple> is in the HTML. The zone div has onclick="document.getElementById('file-input').click()" which programmatically opens the OS file picker. The input's onchange fires with this.files when the user selects files.

Add an accept attribute to the hidden input: accept=".pdf,image/*". This filters the file picker. For drag-and-drop, check file types in addFiles(): if (!allowedTypes.includes(file.type)) return; — the accept attribute does not prevent drag drops.

In addFiles(), create a FormData: const fd = new FormData(); files.forEach(f => fd.append("files", f)); await fetch("/upload", { method: "POST", body: fd });. No Content-Type header needed — the browser sets it automatically with the boundary.

For image files (file.type.startsWith("image/")), use FileReader: const reader = new FileReader(); reader.onload = e => { const img = document.createElement("img"); img.src = e.target.result; item.prepend(img); }; reader.readAsDataURL(file);

Yes. Click "JSX" for a React component. In React, manage the files array in useState. Wire onDragOver, onDragLeave, onDrop props to the div and onChange to the input. Call setFiles(prev => [...prev, ...newFiles]) in each handler.