Simple Drag & Drop File Upload Interface with HTML, CSS & JavaScript
March 5th, 2020In this tutorial, you'll create a "drag and drop" file upload form using HTML, CSS & JavaScript. This makes use of the HTML Drag & Drop API.
Video Tutorial
Source Code
You can find the source code for this video below. Alternatively, browse it on CodePen.
index.html
<!DOCTYPE html>
<head>
<title>Drag and Drop File Upload</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8">
<link rel="shortcut icon" href="/assets/favicon.ico">
<link rel="stylesheet" href="./src/main.css">
</head>
<body>
<div class="drop-zone">
<span class="drop-zone__prompt">Drop file here or click to upload</span>
<input type="file" name="myFile" class="drop-zone__input">
</div>
<script src="./src/main.js"></script>
</body>
main.css
.drop-zone {
max-width: 200px;
height: 200px;
padding: 25px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-family: "Quicksand", sans-serif;
font-weight: 500;
font-size: 20px;
cursor: pointer;
color: #cccccc;
border: 4px dashed #009578;
border-radius: 10px;
}
.drop-zone--over {
border-style: solid;
}
.drop-zone__input {
display: none;
}
.drop-zone__thumb {
width: 100%;
height: 100%;
border-radius: 10px;
overflow: hidden;
background-color: #cccccc;
background-size: cover;
position: relative;
}
.drop-zone__thumb::after {
content: attr(data-label);
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 5px 0;
color: #ffffff;
background: rgba(0, 0, 0, 0.75);
font-size: 14px;
text-align: center;
}
main.js
document.querySelectorAll(".drop-zone__input").forEach((inputElement) => {
const dropZoneElement = inputElement.closest(".drop-zone");
dropZoneElement.addEventListener("click", (e) => {
inputElement.click();
});
inputElement.addEventListener("change", (e) => {
if (inputElement.files.length) {
updateThumbnail(dropZoneElement, inputElement.files[0]);
}
});
dropZoneElement.addEventListener("dragover", (e) => {
e.preventDefault();
dropZoneElement.classList.add("drop-zone--over");
});
["dragleave", "dragend"].forEach((type) => {
dropZoneElement.addEventListener(type, (e) => {
dropZoneElement.classList.remove("drop-zone--over");
});
});
dropZoneElement.addEventListener("drop", (e) => {
e.preventDefault();
if (e.dataTransfer.files.length) {
inputElement.files = e.dataTransfer.files;
updateThumbnail(dropZoneElement, e.dataTransfer.files[0]);
}
dropZoneElement.classList.remove("drop-zone--over");
});
});
/**
* Updates the thumbnail on a drop zone element.
*
* @param {HTMLElement} dropZoneElement
* @param {File} file
*/
function updateThumbnail(dropZoneElement, file) {
let thumbnailElement = dropZoneElement.querySelector(".drop-zone__thumb");
// First time - remove the prompt
if (dropZoneElement.querySelector(".drop-zone__prompt")) {
dropZoneElement.querySelector(".drop-zone__prompt").remove();
}
// First time - there is no thumbnail element, so lets create it
if (!thumbnailElement) {
thumbnailElement = document.createElement("div");
thumbnailElement.classList.add("drop-zone__thumb");
dropZoneElement.appendChild(thumbnailElement);
}
thumbnailElement.dataset.label = file.name;
// Show thumbnail for image files
if (file.type.startsWith("image/")) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
thumbnailElement.style.backgroundImage = `url('${reader.result}')`;
};
} else {
thumbnailElement.style.backgroundImage = null;
}
}
If you have any questions about this code, please leave a comment on the video.