Uploading photos in JavaScript web applications involves both client-side and server-side processes. On the client side, developers typically use the <input type="file"> element (optionally with accept="image/*" and multiple attributes) to let users select one or more image files. JavaScript’s File API and FileReader enable previewing images before upload by converting them to base64-encoded URLs.
For sending images to a server, the FormData object is commonly used, allowing files to be transmitted via fetch or XMLHttpRequest. On the backend, a dedicated endpoint receives the uploaded files, processes them, and stores them locally or in cloud storage, returning a response with upload status or file URLs.
This tutorial demonstrates these concepts by building a simple image uploader with JavaScript, covering file input, image preview, drag-and-drop, and the basics of sending images to a server.
Join thousands of businesses transforming their digital asset management with Cloudinary. Sign up for free today!
Uploading an Image Using The File API
The File API is a Web API that enables web applications to access files and their contents. Developers can implement this feature in two ways:
- An
inputelement with atype="file"to let the user choose one or more files from their device storage. - Using the HTML Drag and Drop API to allow users to upload files to a web application.
In the steps to follow, we’ll explain how to implement a simple image uploader in HTML, CSS, and JavaScript.
Step 1 – HTML and CSS Structure
First, let’s create the structure of what the web page we’ll use in this example will look like. Create a file named index.html and add the following code to it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Javascript Image Upload</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="container">
<input type="file" id="fileUpload" accept="image/*">
</div>
<div class="image-container">
<img id="output" src="" alt="">
</div>
</body>
<script src="index.js"></script>
</html>
Next, create another file named index.css and add the following code to it:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-direction: column;
background-color: white;
font-family: Arial, sans-serif;
}
.container {
display: flex;
justify-content: center;
align-items: center;
border: 2px solid #ccc;
padding: 20px;
margin-bottom: 30px;
border-radius: 10px;
background-color: #f9f9f9;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
#fileUpload {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
}
Here’s what’s going on in the two blocks of code above.
- The HTML code defines the structure of the page.
- The HTML also includes a link to an external
index.cssfor styling and anindex.jsfile which will handle the functionality for image uploading and displaying, which we will create in a moment.
Here’s what the result looks like in the browser:
Step 2 – Handle Image Upload Using JavaScript
In the same folder with the previous HTML and CSS files, create another file named index.js and add the following code to it:
const fileInput = document.getElementById("fileUpload")
const imageOutput = document.getElementById("output");
fileInput.addEventListener("change", async () => {
let [file] = fileInput.files
const reader = new FileReader();
reader.onload = (e) => {
imageOutput.src = e.target.result;
};
reader.onerror = (err) => {
console.error("Error reading file:", err);
alert("An error occurred while reading the file.");
};
reader.readAsDataURL(file);
})
Let’s break down what’s going on in that code block:
- The first part of the code selects the input and
imgelements using their respective IDs. - Next, we added an event listener to the
fileInputelement to listen for the “change” event, which triggers when a user selects a file. - Finally, when a file is selected, a
FileReaderobject reads the file as a Data URL. Once the file is read, the img elementsrcattribute is set to the resulting Data URL, displaying the selected image.
Specify Acceptable File Types for Upload
We can specify the acceptable file types the input element should accept using the accept attribute. The value is a comma-separated list of allowed file extensions or MIME types. For example, accept="image/png, image/jpeg" or accept=".png, .jpg, .jpeg" accept PNG or JPEG files. We can also use a wildcard to accept any type of image file extension, as shown below:
<input type="file" id="fileUpload" accept="image/*">
Accepting multiple files
By default, a user can only upload a single file. However, we can use the multiple Boolean attribute to allow users to upload more than one file at a time.
<input type="file" id="fileUpload" multiple>
Previewing Multiple Images Before Upload
When allowing multiple file uploads, you can preview all selected images before uploading them. Use JavaScript’s File API and FileReader to loop through the selected files and display each image in the browser:
<input type="file" id="imageUpload" accept="image/*" multiple>
<div id="imagePreview"></div>
const imageUpload = document.getElementById('imageUpload');
const imagePreview = document.getElementById('imagePreview');
imageUpload.addEventListener('change', (event) => {
const files = event.target.files;
imagePreview.innerHTML = ''; // Clear previous previews
for (const file of files) {
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = (e) => {
const img = document.createElement('img');
img.src = e.target.result;
img.style.maxWidth = '200px'; // Example styling
imagePreview.appendChild(img);
};
reader.readAsDataURL(file);
}
}
});
Upload an Image Using Drag and Drop
The HTML drag-and-drop interface allows web apps to implement drag-and-drop through the following two steps:
- Specify a target element for the file drop, also known as the “drop zone”.
- Specify event handlers for the “drop” and “dragover” events.
Let’s see how to do this in the series of steps below.
Step 1 – HTML and CSS Structure
Open the index.html file and replace its contents with the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drag and drop image upload</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div class="container">
<div class="drag-drop-area" id="dragDropArea">
<p>Drag & Drop your files here</p>
</div>
<div id="output"></div>
</div>
<script src="script.js"></script>
</body>
</html>
Then, in the index.css file, replace the code with the following:
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.container {
text-align: center;
}
.drag-drop-area {
border: 2px dashed #ccc;
padding: 20px;
border-radius: 10px;
background-color: white;
cursor: pointer;
width: 300px;
margin: 20px auto;
position: relative;
}
.drag-drop-area p {
margin: 10px 0;
}
#fileInput {
display: none;
}
#output {
margin-top: 20px;
}
#output img {
max-width: 100%;
height: auto;
}
Here’s what the webpage looks like:
Step 2 – Add JavaScript
In the index.js file, replace the code with the following:
const dragDropArea = document.getElementById("dragDropArea");
const output = document.getElementById("output");
// Step 1 - Add an event listener for the dragover event
dragDropArea.addEventListener("dragover", (e) => {
e.preventDefault(); // This turns off the browser's default drag and drop handler.
dragDropArea.classList.add("dragover");
});
// Step 2 - Add an event listener for the drop event
dragDropArea.addEventListener("drop", (e) => {
e.preventDefault();
dragDropArea.classList.remove("dragover");
const files = e.dataTransfer.files;
if (files.length === 0) {
alert("No files selected.");
return;
}
output.innerHTML = "";
for (const file of files) {
if (!file.type.startsWith("image/")) {
alert("Only image files are allowed.");
return;
}
const reader = new FileReader();
reader.onload = (e) => {
const img = document.createElement("img");
img.src = e.target.result;
output.appendChild(img);
};
reader.onerror = (err) => {
console.error("Error reading file:", err);
alert("An error occurred while reading the file.");
};
reader.readAsDataURL(file);
}
});
Again, let’s break down the logic behind the code:
- The first part of the code selects two HTML elements: the drag-drop area and an output area.
- Next, we create event handlers to handle the “drop” and “dragover” events.
- We also use the
DataTransferobject (ine.dataTransfer.files) to access the data being dragged during the drag-and-drop operation. - Then, we process the dropped files using the
FileReadermethod and create an img element to display the uploaded image file.
Uploading Images to a Server Using JavaScript
After selecting and previewing images, you often need to upload them to a server for storage or further processing. JavaScript’s FormData object makes this easy by allowing you to append files and other form fields, then send them via fetch or XMLHttpRequest:
// Assuming 'files' contains the selected image files
const formData = new FormData();
for (const file of files) {
formData.append('images', file); // 'images' is the field name on the server
}
fetch('/upload-endpoint', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log('Upload success:', data))
.catch(error => console.error('Upload error:', error));
On the server side, you’ll need an endpoint (for example, in Node.js, Python, or PHP) to receive the uploaded files, save them to disk or cloud storage, and return a response with the upload status or file URLs.
Wrapping Up
In this article, we explored two methods of uploading image files in a web application using HTML, CSS, and JavaScript: the traditional file input approach and the interactive drag-and-drop method. While several libraries simplify the process, knowing how to write the code on your own will allow you to gain deeper insights into browser APIs and improve your overall web app development skills.
Empower your development team with Cloudinary’s easy-to-use APIs and SDKs. Sign up for free today!