<div class="multi-upload">
<div class="drop-area" id="dropArea">
<svg class="upload-icon" viewBox="0 0 24 24" width="48" height="48" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>
<h3>Drag & Drop Images Here</h3>
<p>or <span class="browse-btn">browse files</span> from your computer</p>
<input type="file" id="fileElem" multiple accept="image/*" class="file-input">
</div>
<div class="gallery" id="gallery"></div>
</div>
.multi-upload {
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
width: 100%;
max-width: 600px;
margin: 0 auto;
}
.drop-area {
border: 2px dashed #d1d5db;
border-radius: 16px;
padding: 40px;
text-align: center;
background: #f9fafb;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.drop-area.highlight {
border-color: #3b82f6;
background: #eff6ff;
}
.upload-icon {
color: #9ca3af;
margin-bottom: 15px;
}
.drop-area h3 {
margin: 0 0 10px 0;
color: #1f2937;
}
.drop-area p {
margin: 0;
color: #6b7280;
font-size: 0.95rem;
}
.browse-btn {
color: #2563eb;
font-weight: 600;
text-decoration: underline;
}
.file-input {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0;
cursor: pointer;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 15px;
margin-top: 20px;
}
.gallery-item {
position: relative;
width: 100%;
height: 100px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);
}
.gallery-item img {
width: 100%;
height: 100%;
object-fit: cover;
}
.remove-file {
position: absolute;
top: 4px;
right: 4px;
background: rgba(0,0,0,0.6);
color: white;
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
cursor: pointer;
}
const dropArea = document.getElementById("dropArea");
const fileElem = document.getElementById("fileElem");
const gallery = document.getElementById("gallery");
// Prevent default drag behaviors
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Highlight drop area when item is dragged over it
["dragenter", "dragover"].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
["dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
function highlight() {
dropArea.classList.add("highlight");
}
function unhighlight() {
dropArea.classList.remove("highlight");
}
// Handle dropped files
dropArea.addEventListener("drop", handleDrop, false);
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
// Handle selected files via input
fileElem.addEventListener("change", function() {
handleFiles(this.files);
});
function handleFiles(files) {
([...files]).forEach(previewFile);
}
function previewFile(file) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = function() {
const img = document.createElement("img");
img.src = reader.result;
const div = document.createElement("div");
div.classList.add("gallery-item");
div.innerHTML = `<span class="remove-file" onclick="this.parentElement.remove()">×</span>`;
div.appendChild(img);
gallery.appendChild(div);
};
}